aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2014-02-17 11:21:18 -0800
committerAaron Patterson <aaron.patterson@gmail.com>2014-02-17 11:21:18 -0800
commitfe42effb11a97cf19777d7b0dba7e1e2dfd3316c (patch)
tree388f48bc682802cbcae53a0d570d2c8587bbb98b /actionmailer
parent5ac2879b08b05b7f6eaebc5473e62b4576f84a3f (diff)
parent3e3ed1ede51f4d2f7f1d30b3754072b1121d5394 (diff)
downloadrails-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.md24
-rw-r--r--actionmailer/README.rdoc2
-rw-r--r--actionmailer/lib/action_mailer/base.rb43
-rw-r--r--actionmailer/lib/action_mailer/preview.rb43
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb2
-rw-r--r--actionmailer/test/base_test.rb59
-rw-r--r--actionmailer/test/delivery_methods_test.rb29
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