aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer
diff options
context:
space:
mode:
Diffstat (limited to 'actionmailer')
-rw-r--r--actionmailer/CHANGELOG.md13
-rw-r--r--actionmailer/actionmailer.gemspec1
-rw-r--r--actionmailer/lib/action_mailer.rb2
-rw-r--r--actionmailer/lib/action_mailer/base.rb8
-rw-r--r--actionmailer/lib/action_mailer/delivery_job.rb11
-rw-r--r--actionmailer/lib/action_mailer/message_delivery.rb45
-rw-r--r--actionmailer/lib/action_mailer/preview.rb2
-rw-r--r--actionmailer/lib/action_mailer/test_case.rb7
-rw-r--r--actionmailer/test/abstract_unit.rb7
-rw-r--r--actionmailer/test/assert_select_email_test.rb47
-rw-r--r--actionmailer/test/base_test.rb8
-rw-r--r--actionmailer/test/mailers/delayed_mailer.rb6
-rw-r--r--actionmailer/test/message_delivery_test.rb82
13 files changed, 225 insertions, 14 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index ab93745f60..e6952a4b3b 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,16 @@
+* Added #deliver_later in addition to #deliver, which will enqueue a job to render and
+ deliver the mail instead of delivering it right at that moment. The job is enqueued
+ using the new Active Job framework in Rails, and will use whatever queue is configured for Rails.
+
+ *DHH/Abdelkader Boudih/Cristian Bica*
+
+
+* Make ActionMailer::Previews methods class methods. Previously they were
+ instance methods and ActionMailer tries to render a message when they
+ are called.
+
+ *Cristian Bica*
+
* Deprecate `*_path` helpers in email views. When used they generate
non-working links and are not the intention of most developers. Instead
we recommend to use `*_url` helper.
diff --git a/actionmailer/actionmailer.gemspec b/actionmailer/actionmailer.gemspec
index 01d97b7213..8452348e11 100644
--- a/actionmailer/actionmailer.gemspec
+++ b/actionmailer/actionmailer.gemspec
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
s.add_dependency 'actionview', version
s.add_dependency 'mail', ['~> 2.5', '>= 2.5.4']
+ s.add_dependency 'rails-dom-testing'
end
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 83969d4074..b994ef3182 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -45,4 +45,6 @@ module ActionMailer
autoload :Previews, 'action_mailer/preview'
autoload :TestCase
autoload :TestHelper
+ autoload :MessageDelivery
+ autoload :DeliveryJob
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index bc540aece0..9aae14ec8c 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -548,8 +548,8 @@ module ActionMailer
end
def method_missing(method_name, *args) # :nodoc:
- if respond_to?(method_name)
- new(method_name, *args).message
+ if action_methods.include?(method_name.to_s)
+ MessageDelivery.new(self, method_name, *args)
else
super
end
@@ -586,6 +586,10 @@ module ActionMailer
class NullMail #:nodoc:
def body; '' end
+ def respond_to?(string, include_all=false)
+ true
+ end
+
def method_missing(*args)
nil
end
diff --git a/actionmailer/lib/action_mailer/delivery_job.rb b/actionmailer/lib/action_mailer/delivery_job.rb
new file mode 100644
index 0000000000..b2cfa245fd
--- /dev/null
+++ b/actionmailer/lib/action_mailer/delivery_job.rb
@@ -0,0 +1,11 @@
+require 'active_job'
+
+module ActionMailer
+ class DeliveryJob < ActiveJob::Base
+ queue_as :mailers
+
+ def perform(mailer, mail_method, delivery_method, *args)
+ mailer.constantize.public_send(mail_method, *args).send(delivery_method)
+ end
+ end
+end
diff --git a/actionmailer/lib/action_mailer/message_delivery.rb b/actionmailer/lib/action_mailer/message_delivery.rb
new file mode 100644
index 0000000000..80a0517bff
--- /dev/null
+++ b/actionmailer/lib/action_mailer/message_delivery.rb
@@ -0,0 +1,45 @@
+require 'delegate'
+
+module ActionMailer
+ class MessageDelivery < Delegator
+ def initialize(mailer, mail_method, *args)
+ @mailer = mailer
+ @mail_method = mail_method
+ @args = args
+ end
+
+ def __getobj__
+ @obj ||= @mailer.send(:new, @mail_method, *@args).message
+ end
+
+ def __setobj__(obj)
+ @obj = obj
+ end
+
+ def message #:nodoc:
+ __getobj__
+ end
+
+ def deliver_later!(options={})
+ enqueue_delivery :deliver!, options
+ end
+
+ def deliver_later(options={})
+ enqueue_delivery :deliver, options
+ end
+
+ private
+ def enqueue_delivery(delivery_method, options={})
+ args = @mailer.name, @mail_method.to_s, delivery_method.to_s, *@args
+ enqueue_method = :enqueue
+ if options[:at]
+ enqueue_method = :enqueue_at
+ args.unshift options[:at]
+ elsif options[:in]
+ enqueue_method = :enqueue_in
+ args.unshift options[:in]
+ end
+ ActionMailer::DeliveryJob.send enqueue_method, *args
+ end
+ end
+end
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
index 33de1dc049..44cf6665ba 100644
--- a/actionmailer/lib/action_mailer/preview.rb
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -22,7 +22,9 @@ module ActionMailer
# :nodoc:
mattr_accessor :preview_interceptors, instance_writer: false
self.preview_interceptors = []
+ end
+ module ClassMethods
# 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) }
diff --git a/actionmailer/lib/action_mailer/test_case.rb b/actionmailer/lib/action_mailer/test_case.rb
index a5442c0316..d507032838 100644
--- a/actionmailer/lib/action_mailer/test_case.rb
+++ b/actionmailer/lib/action_mailer/test_case.rb
@@ -1,4 +1,5 @@
require 'active_support/test_case'
+require 'rails-dom-testing'
module ActionMailer
class NonInferrableMailerError < ::StandardError
@@ -15,6 +16,7 @@ module ActionMailer
include ActiveSupport::Testing::ConstantLookup
include TestHelper
+ include Rails::Dom::Testing::Assertions::SelectorAssertions
included do
class_attribute :_mailer_class
@@ -55,14 +57,13 @@ module ActionMailer
protected
def initialize_test_deliveries
- @old_delivery_method = ActionMailer::Base.delivery_method
+ set_delivery_method :test
@old_perform_deliveries = ActionMailer::Base.perform_deliveries
- ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
end
def restore_test_deliveries
- ActionMailer::Base.delivery_method = @old_delivery_method
+ restore_delivery_method
ActionMailer::Base.perform_deliveries = @old_perform_deliveries
ActionMailer::Base.deliveries.clear
end
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 1281b1bcfc..c549545674 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -26,7 +26,7 @@ I18n.enforce_available_locales = false
FIXTURE_LOAD_PATH = File.expand_path('fixtures', File.dirname(__FILE__))
ActionMailer::Base.view_paths = FIXTURE_LOAD_PATH
-class Rails
+module Rails
def self.root
File.expand_path('../', File.dirname(__FILE__))
end
@@ -51,8 +51,3 @@ def jruby_skip(message = '')
end
require 'mocha/setup' # FIXME: stop using mocha
-
-# FIXME: we have tests that depend on run order, we should fix that and
-# remove this method call.
-require 'active_support/test_case'
-ActiveSupport::TestCase.my_tests_are_order_dependent!
diff --git a/actionmailer/test/assert_select_email_test.rb b/actionmailer/test/assert_select_email_test.rb
new file mode 100644
index 0000000000..57ae3436e1
--- /dev/null
+++ b/actionmailer/test/assert_select_email_test.rb
@@ -0,0 +1,47 @@
+require 'abstract_unit'
+
+class AssertSelectEmailTest < ActionMailer::TestCase
+ class AssertSelectMailer < ActionMailer::Base
+ def test(html)
+ mail body: html, content_type: "text/html",
+ subject: "Test e-mail", from: "test@test.host", to: "test <test@test.host>"
+ end
+ end
+
+ class AssertMultipartSelectMailer < ActionMailer::Base
+ def test(options)
+ mail subject: "Test e-mail", from: "test@test.host", to: "test <test@test.host>" do |format|
+ format.text { render text: options[:text] }
+ format.html { render text: options[:html] }
+ end
+ end
+ end
+
+ #
+ # Test assert_select_email
+ #
+
+ def test_assert_select_email
+ assert_raise ActiveSupport::TestCase::Assertion do
+ assert_select_email {}
+ end
+
+ AssertSelectMailer.test("<div><p>foo</p><p>bar</p></div>").deliver
+ assert_select_email do
+ assert_select "div:root" do
+ assert_select "p:first-child", "foo"
+ assert_select "p:last-child", "bar"
+ end
+ end
+ end
+
+ def test_assert_select_email_multipart
+ AssertMultipartSelectMailer.test(html: "<div><p>foo</p><p>bar</p></div>", text: 'foo bar').deliver
+ assert_select_email do
+ assert_select "div:root" do
+ assert_select "p:first-child", "foo"
+ assert_select "p:last-child", "bar"
+ end
+ end
+ end
+end
diff --git a/actionmailer/test/base_test.rb b/actionmailer/test/base_test.rb
index 6116d1e29f..fc24639bf4 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -11,6 +11,8 @@ require 'mailers/asset_mailer'
class BaseTest < ActiveSupport::TestCase
setup do
+ @original_delivery_method = ActionMailer::Base.delivery_method
+ ActionMailer::Base.delivery_method = :test
@original_asset_host = ActionMailer::Base.asset_host
@original_assets_dir = ActionMailer::Base.assets_dir
end
@@ -19,6 +21,7 @@ class BaseTest < ActiveSupport::TestCase
ActionMailer::Base.asset_host = @original_asset_host
ActionMailer::Base.assets_dir = @original_assets_dir
BaseMailer.deliveries.clear
+ ActionMailer::Base.delivery_method = @original_delivery_method
end
test "method call to mail does not raise error" do
@@ -240,7 +243,7 @@ class BaseTest < ActiveSupport::TestCase
end
end
- e = assert_raises(RuntimeError) { LateAttachmentMailer.welcome }
+ e = assert_raises(RuntimeError) { LateAttachmentMailer.welcome.message }
assert_match(/Can't add attachments after `mail` was called./, e.message)
end
@@ -252,7 +255,7 @@ class BaseTest < ActiveSupport::TestCase
end
end
- e = assert_raises(RuntimeError) { LateInlineAttachmentMailer.welcome }
+ e = assert_raises(RuntimeError) { LateInlineAttachmentMailer.welcome.message }
assert_match(/Can't add attachments after `mail` was called./, e.message)
end
@@ -468,7 +471,6 @@ class BaseTest < ActiveSupport::TestCase
end
test "calling deliver on the action should increment the deliveries collection if using the test mailer" do
- BaseMailer.delivery_method = :test
BaseMailer.welcome.deliver
assert_equal(1, BaseMailer.deliveries.length)
end
diff --git a/actionmailer/test/mailers/delayed_mailer.rb b/actionmailer/test/mailers/delayed_mailer.rb
new file mode 100644
index 0000000000..62d4baa434
--- /dev/null
+++ b/actionmailer/test/mailers/delayed_mailer.rb
@@ -0,0 +1,6 @@
+class DelayedMailer < ActionMailer::Base
+
+ def test_message(*)
+ mail(from: 'test-sender@test.com', to: 'test-receiver@test.com', subject: 'Test Subject', body: 'Test Body')
+ end
+end
diff --git a/actionmailer/test/message_delivery_test.rb b/actionmailer/test/message_delivery_test.rb
new file mode 100644
index 0000000000..a097d0e84d
--- /dev/null
+++ b/actionmailer/test/message_delivery_test.rb
@@ -0,0 +1,82 @@
+# encoding: utf-8
+gem 'activejob'
+require 'active_job'
+require 'abstract_unit'
+require 'minitest/mock'
+require_relative 'mailers/delayed_mailer'
+
+class MessageDeliveryTest < ActiveSupport::TestCase
+
+ setup do
+ @previous_logger = ActiveJob::Base.logger
+ @previous_delivery_method = ActionMailer::Base.delivery_method
+ ActionMailer::Base.delivery_method = :test
+ ActiveJob::Base.logger = Logger.new(nil)
+ @mail = DelayedMailer.test_message(1, 2, 3)
+ ActionMailer::Base.deliveries.clear
+ end
+
+ teardown do
+ ActiveJob::Base.logger = @previous_logger
+ ActionMailer::Base.delivery_method = @previous_delivery_method
+ end
+
+ test 'should have a message' do
+ assert @mail.message
+ end
+
+ test 'its message should be a Mail::Message' do
+ assert_equal Mail::Message , @mail.message.class
+ end
+
+ test 'should respond to .deliver' do
+ assert_respond_to @mail, :deliver
+ end
+
+ test 'should respond to .deliver!' do
+ assert_respond_to @mail, :deliver!
+ end
+
+ test 'should respond to .deliver_later' do
+ assert_respond_to @mail, :deliver_later
+ end
+
+ test 'should respond to .deliver_later!' do
+ assert_respond_to @mail, :deliver_later!
+ end
+
+ test 'should enqueue and run correctly in activejob' do
+ @mail.deliver_later!
+ assert_equal 1 , ActionMailer::Base.deliveries.size
+ end
+
+ test 'should enqueue the email with :deliver delivery method' do
+ ret = ActionMailer::DeliveryJob.stub :enqueue, ->(*args){ args } do
+ @mail.deliver_later
+ end
+ assert_equal ['DelayedMailer', 'test_message', 'deliver', 1, 2, 3], ret
+ end
+
+ test 'should enqueue the email with :deliver! delivery method' do
+ ret = ActionMailer::DeliveryJob.stub :enqueue, ->(*args){ args } do
+ @mail.deliver_later!
+ end
+ assert_equal ['DelayedMailer', 'test_message', 'deliver!', 1, 2, 3], ret
+ end
+
+ test 'should enqueue a delivery with a delay' do
+ ret = ActionMailer::DeliveryJob.stub :enqueue_in, ->(*args){ args } do
+ @mail.deliver_later in: 600
+ end
+ assert_equal [600, 'DelayedMailer', 'test_message', 'deliver', 1, 2, 3], ret
+ end
+
+ test 'should enqueue a delivery at a specific time' do
+ later_time = Time.now.to_i + 3600
+ ret = ActionMailer::DeliveryJob.stub :enqueue_at, ->(*args){ args } do
+ @mail.deliver_later at: later_time
+ end
+ assert_equal [later_time, 'DelayedMailer', 'test_message', 'deliver', 1, 2, 3], ret
+ end
+
+end