diff options
author | Aaron Patterson <aaron.patterson@gmail.com> | 2014-02-17 11:21:18 -0800 |
---|---|---|
committer | Aaron Patterson <aaron.patterson@gmail.com> | 2014-02-17 11:21:18 -0800 |
commit | fe42effb11a97cf19777d7b0dba7e1e2dfd3316c (patch) | |
tree | 388f48bc682802cbcae53a0d570d2c8587bbb98b /actionmailer | |
parent | 5ac2879b08b05b7f6eaebc5473e62b4576f84a3f (diff) | |
parent | 3e3ed1ede51f4d2f7f1d30b3754072b1121d5394 (diff) | |
download | rails-fe42effb11a97cf19777d7b0dba7e1e2dfd3316c.tar.gz rails-fe42effb11a97cf19777d7b0dba7e1e2dfd3316c.tar.bz2 rails-fe42effb11a97cf19777d7b0dba7e1e2dfd3316c.zip |
Merge branch 'master' into adequaterecord
* master: (311 commits)
Add a missing changelog entry for #13981 and #14035
Revert "Fixed plugin_generator test"
implements new option :month_format_string for date select helpers [Closes #13618]
add factory methods for empty alias trackers
guarantee a list in the alias tracker so we can remove a conditional
stop exposing table_joins
make most parameters to the AliasTracker required
make a singleton for AssociationScope
pass the association and connection to the scope method
pass the tracker down the stack and construct it in the scope method
clean up add_constraints signature
remove the reflection delegate
remove klass delegator
remove railties changes. fixes #14054
remove chain delegate
remove scope_chain delegate
Add verb to sanitization note
fix path shown in mailer's templates
updated Travis build status image url
fix guide active_support_core_extensions. add Note to String#indent [ci skip]
...
Conflicts:
activerecord/lib/active_record/associations/join_dependency.rb
activerecord/test/cases/associations/association_scope_test.rb
Diffstat (limited to 'actionmailer')
-rw-r--r-- | actionmailer/CHANGELOG.md | 24 | ||||
-rw-r--r-- | actionmailer/README.rdoc | 2 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/base.rb | 43 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/preview.rb | 43 | ||||
-rw-r--r-- | actionmailer/lib/action_mailer/railtie.rb | 2 | ||||
-rw-r--r-- | actionmailer/test/base_test.rb | 59 | ||||
-rw-r--r-- | actionmailer/test/delivery_methods_test.rb | 29 |
7 files changed, 173 insertions, 29 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md index 1867a392eb..5a61746700 100644 --- a/actionmailer/CHANGELOG.md +++ b/actionmailer/CHANGELOG.md @@ -1,4 +1,26 @@ -* Add mailer previews feature based on 37 Signals mail_view gem +* Support the use of underscored symbols when registering interceptors and + observers like we do elsewhere within Rails. + + *Andrew White* + +* Add the ability to intercept emails before previewing in a similar fashion + to how emails can be intercepted before delivery. + + Fixes #13622. + + Example: + + class CSSInlineStyler + def self.previewing_email(message) + # inline CSS styles + end + end + + ActionMailer::Base.register_preview_interceptor CSSInlineStyler + + *Andrew White* + +* Add mailer previews feature based on 37 Signals mail_view gem. *Andrew White* diff --git a/actionmailer/README.rdoc b/actionmailer/README.rdoc index c3dcd3c3e4..e425282fa8 100644 --- a/actionmailer/README.rdoc +++ b/actionmailer/README.rdoc @@ -74,7 +74,7 @@ Or you can just chain the methods together like: == Setting defaults -It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from <tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers e-mail messages has, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed. +It is possible to set default values that will be used in every method in your Action Mailer class. To implement this functionality, you just call the public class method <tt>default</tt> which you get for free from <tt>ActionMailer::Base</tt>. This method accepts a Hash as the parameter. You can use any of the headers email messages have, like <tt>:from</tt> as the key. You can also pass in a string as the key, like "Content-Type", but Action Mailer does this out of the box for you, so you won't need to worry about that. Finally, it is also possible to pass in a Proc that will get evaluated when it is needed. Note that every value you set with this method will get overwritten if you use the same key in your mailer method. diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index a30e3e65da..eb8cca9ee4 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -51,7 +51,7 @@ module ActionMailer # * <tt>mail</tt> - Allows you to specify email to be sent. # # The hash passed to the mail method allows you to specify any header that a <tt>Mail::Message</tt> - # will accept (any valid Email header including optional fields). + # will accept (any valid email header including optional fields). # # The mail method, if not passed a block, will inspect your views and send all the views with # the same name as the method, so the above action would send the +welcome.text.erb+ view @@ -330,6 +330,21 @@ module ActionMailer # An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt> # on a running development server instance. # + # Previews can also be intercepted in a similar manner as deliveries can be by registering + # a preview interceptor that has a <tt>previewing_email</tt> method: + # + # class CssInlineStyler + # def self.previewing_email(message) + # # inline CSS styles + # end + # end + # + # config.action_mailer.register_preview_interceptor :css_inline_styler + # + # Note that interceptors need to be registered both with <tt>register_interceptor</tt> + # and <tt>register_preview_interceptor</tt> if they should operate on both sending and + # previewing emails. + # # = Configuration options # # These options are specified on the class level, like @@ -429,18 +444,30 @@ module ActionMailer end # Register an Observer which will be notified when mail is delivered. - # Either a class or a string can be passed in as the Observer. If a string is passed in - # it will be <tt>constantize</tt>d. + # Either a class, string or symbol can be passed in as the Observer. + # If a string or symbol is passed in it will be camelized and constantized. def register_observer(observer) - delivery_observer = (observer.is_a?(String) ? observer.constantize : observer) + delivery_observer = case observer + when String, Symbol + observer.to_s.camelize.constantize + else + observer + end + Mail.register_observer(delivery_observer) end # Register an Interceptor which will be called before mail is sent. - # Either a class or a string can be passed in as the Interceptor. If a string is passed in - # it will be <tt>constantize</tt>d. + # Either a class, string or symbol can be passed in as the Interceptor. + # If a string or symbol is passed in it will be camelized and constantized. def register_interceptor(interceptor) - delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor) + delivery_interceptor = case interceptor + when String, Symbol + interceptor.to_s.camelize.constantize + else + interceptor + end + Mail.register_interceptor(delivery_interceptor) end @@ -737,7 +764,7 @@ module ActionMailer m.charset = charset = headers[:charset] # Set configure delivery behavior - wrap_delivery_behavior!(headers.delete(:delivery_method),headers.delete(:delivery_method_options)) + wrap_delivery_behavior!(headers.delete(:delivery_method), headers.delete(:delivery_method_options)) # Assign all headers except parts_order, content_type and body assignable = headers.except(:parts_order, :content_type, :body, :template_name, :template_path) diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb index ecceaf8c70..fde0e86f5b 100644 --- a/actionmailer/lib/action_mailer/preview.rb +++ b/actionmailer/lib/action_mailer/preview.rb @@ -9,7 +9,32 @@ module ActionMailer # # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews" # - class_attribute :preview_path, instance_writer: false + mattr_accessor :preview_path, instance_writer: false + + # :nodoc: + mattr_accessor :preview_interceptors, instance_writer: false + self.preview_interceptors = [] + + # Register one or more Interceptors which will be called before mail is previewed. + def register_preview_interceptors(*interceptors) + interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) } + end + + # Register am Interceptor which will be called before mail is previewed. + # Either a class or a string can be passed in as the Interceptor. If a + # string is passed in it will be <tt>constantize</tt>d. + def register_preview_interceptor(interceptor) + preview_interceptor = case interceptor + when String, Symbol + interceptor.to_s.camelize.constantize + else + interceptor + end + + unless preview_interceptors.include?(preview_interceptor) + preview_interceptors << preview_interceptor + end + end end end @@ -23,10 +48,14 @@ module ActionMailer descendants end - # Returns the mail object for the given email name + # Returns the mail object for the given email name. The registered preview + # interceptors will be informed so that they can transform the message + # as they would if the mail was actually being delivered. def call(email) preview = self.new - preview.public_send(email) + message = preview.public_send(email) + inform_preview_interceptors(message) + message end # Returns all of the available email previews @@ -56,7 +85,7 @@ module ActionMailer protected def load_previews #:nodoc: - if preview_path? + if preview_path Dir["#{preview_path}/**/*_preview.rb"].each{ |file| require_dependency file } end end @@ -65,8 +94,10 @@ module ActionMailer Base.preview_path end - def preview_path? #:nodoc: - Base.preview_path? + def inform_preview_interceptors(message) #:nodoc: + Base.preview_interceptors.each do |interceptor| + interceptor.previewing_email(message) + end end end end diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb index c893ddfef5..8d1e40297b 100644 --- a/actionmailer/lib/action_mailer/railtie.rb +++ b/actionmailer/lib/action_mailer/railtie.rb @@ -46,7 +46,7 @@ module ActionMailer end config.after_initialize do - if ActionMailer::Base.preview_path? + if ActionMailer::Base.preview_path ActiveSupport::Dependencies.autoload_paths << ActionMailer::Base.preview_path end end diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb index c1759d9b92..02707d0b5f 100644 --- a/actionmailer/test/base_test.rb +++ b/actionmailer/test/base_test.rb @@ -530,6 +530,13 @@ class BaseTest < ActiveSupport::TestCase mail.deliver end + test "you can register an observer using its symbolized underscored name to the mail object that gets informed on email delivery" do + ActionMailer::Base.register_observer(:"base_test/my_observer") + mail = BaseMailer.welcome + MyObserver.expects(:delivered_email).with(mail) + mail.deliver + end + test "you can register multiple observers to the mail object that both get informed on email delivery" do ActionMailer::Base.register_observers("BaseTest::MyObserver", MySecondObserver) mail = BaseMailer.welcome @@ -539,12 +546,18 @@ class BaseTest < ActiveSupport::TestCase end class MyInterceptor - def self.delivering_email(mail) - end + def self.delivering_email(mail); end + def self.previewing_email(mail); end end class MySecondInterceptor - def self.delivering_email(mail) + def self.delivering_email(mail); end + def self.previewing_email(mail); end + end + + class BaseMailerPreview < ActionMailer::Preview + def welcome + BaseMailer.welcome end end @@ -562,6 +575,13 @@ class BaseTest < ActiveSupport::TestCase mail.deliver end + test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before delivery" do + ActionMailer::Base.register_interceptor(:"base_test/my_interceptor") + mail = BaseMailer.welcome + MyInterceptor.expects(:delivering_email).with(mail) + mail.deliver + end + test "you can register multiple interceptors to the mail object that both get passed the mail object before delivery" do ActionMailer::Base.register_interceptors("BaseTest::MyInterceptor", MySecondInterceptor) mail = BaseMailer.welcome @@ -570,6 +590,39 @@ class BaseTest < ActiveSupport::TestCase mail.deliver end + test "you can register a preview interceptor to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor(MyInterceptor) + mail = BaseMailer.welcome + BaseMailerPreview.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register a preview interceptor using its stringified name to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor("BaseTest::MyInterceptor") + mail = BaseMailer.welcome + BaseMailerPreview.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register an interceptor using its symbolized underscored name to the mail object that gets passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptor(:"base_test/my_interceptor") + mail = BaseMailer.welcome + BaseMailerPreview.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + + test "you can register multiple preview interceptors to the mail object that both get passed the mail object before previewing" do + ActionMailer::Base.register_preview_interceptors("BaseTest::MyInterceptor", MySecondInterceptor) + mail = BaseMailer.welcome + BaseMailerPreview.stubs(:welcome).returns(mail) + MyInterceptor.expects(:previewing_email).with(mail) + MySecondInterceptor.expects(:previewing_email).with(mail) + BaseMailerPreview.call(:welcome) + end + test "being able to put proc's into the defaults hash and they get evaluated on mail sending" do mail1 = ProcMailer.welcome['X-Proc-Method'] yesterday = 1.day.ago diff --git a/actionmailer/test/delivery_methods_test.rb b/actionmailer/test/delivery_methods_test.rb index 20412c7bb2..609903620b 100644 --- a/actionmailer/test/delivery_methods_test.rb +++ b/actionmailer/test/delivery_methods_test.rb @@ -38,8 +38,10 @@ class DefaultsDeliveryMethodsTest < ActiveSupport::TestCase end test "default sendmail settings" do - settings = {location: '/usr/sbin/sendmail', - arguments: '-i -t'} + settings = { + location: '/usr/sbin/sendmail', + arguments: '-i -t' + } assert_equal settings, ActionMailer::Base.sendmail_settings end end @@ -138,13 +140,15 @@ class MailDeliveryTest < ActiveSupport::TestCase end test "default delivery options can be overridden per mail instance" do - settings = { address: "localhost", - port: 25, - domain: 'localhost.localdomain', - user_name: nil, - password: nil, - authentication: nil, - enable_starttls_auto: true } + settings = { + address: "localhost", + port: 25, + domain: 'localhost.localdomain', + user_name: nil, + password: nil, + authentication: nil, + enable_starttls_auto: true + } assert_equal settings, ActionMailer::Base.smtp_settings overridden_options = {user_name: "overridden", password: "somethingobtuse"} mail_instance = DeliveryMailer.welcome(delivery_method_options: overridden_options) @@ -164,6 +168,13 @@ class MailDeliveryTest < ActiveSupport::TestCase end end + test "undefined delivery methods raises errors" do + DeliveryMailer.delivery_method = nil + assert_raise RuntimeError do + DeliveryMailer.welcome.deliver + end + end + test "does not perform deliveries if requested" do DeliveryMailer.perform_deliveries = false DeliveryMailer.deliveries.clear |