Skip to content

Add MailDeliveryJob for unified mail delivery #34591

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion actionmailer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
* Deliver parameterized mail with `ActionMailer::DeliveryJob` and remove `ActionMailer::Parameterized::DeliveryJob`.
* Add `MailDeliveryJob` for delivering both regular and parameterized mail. Deprecate using `DeliveryJob` and `Parameterized::DeliveryJob`.

*Gannon McGibbon*

Expand Down
1 change: 1 addition & 0 deletions actionmailer/lib/action_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ module ActionMailer
autoload :TestHelper
autoload :MessageDelivery
autoload :DeliveryJob
autoload :MailDeliveryJob

def self.eager_load!
super
Expand Down
2 changes: 1 addition & 1 deletion actionmailer/lib/action_mailer/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ def _protected_ivars # :nodoc:

helper ActionMailer::MailHelper

class_attribute :delivery_job, default: ::ActionMailer::DeliveryJob
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
class_attribute :default_params, default: {
mime_version: "1.0",
charset: "UTF-8",
Expand Down
13 changes: 10 additions & 3 deletions actionmailer/lib/action_mailer/delivery_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ class DeliveryJob < ActiveJob::Base # :nodoc:

rescue_from StandardError, with: :handle_exception_with_mailer_class

def perform(mailer, mail_method, delivery_method, params, *args) #:nodoc:
mailer_class = params ? mailer.constantize.with(params) : mailer.constantize
mailer_class.public_send(mail_method, *args).send(delivery_method)
before_perform do
ActiveSupport::Deprecation.warn <<~MSG.squish
Sending mail with DeliveryJob and Parameterized::DeliveryJob
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Parameterized::DeliveryJob isn't released yet can we instead deprecate just DeliveryJob and then recommend the new one? If you need the params key then you should use the new one.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed Parameterized::DeliveryJob from the warning, but the warning will still happen for parameterized delivery jobs because its a subclass. I assume this is good enough?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that Parameterized::DeliveryJob has never been released so we can delete the code that supported Parameterized::DeliveryJob and anyone who needs a Parameterized::DeliveryJob would use the new MailDeliveryJob instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is released in all versions since 5.1.0

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see I was thinking of this PR 251b9d4 which is only in master.

is deprecated and will be removed in Rails 6.1.
Please use MailDeliveryJob instead.
MSG
end

def perform(mailer, mail_method, delivery_method, *args) #:nodoc:
mailer.constantize.public_send(mail_method, *args).send(delivery_method)
end

private
Expand Down
38 changes: 38 additions & 0 deletions actionmailer/lib/action_mailer/mail_delivery_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require "active_job"

module ActionMailer
# The <tt>ActionMailer::NewDeliveryJob</tt> class is used when you
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this one mention of NewDeliveryJob stuck around even though most others were updated to MailDeliveryJob instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed. Thanks

# want to send emails outside of the request-response cycle. It supports
# sending either parameterized or normal mail.
#
# Exceptions are rescued and handled by the mailer class.
class MailDeliveryJob < ActiveJob::Base # :nodoc:
queue_as { ActionMailer::Base.deliver_later_queue_name }

rescue_from StandardError, with: :handle_exception_with_mailer_class

def perform(mailer, mail_method, delivery_method, args:, params: nil) #:nodoc:
mailer_class = params ? mailer.constantize.with(params) : mailer.constantize
mailer_class.public_send(mail_method, *args).send(delivery_method)
end

private
# "Deserialize" the mailer class name by hand in case another argument
# (like a Global ID reference) raised DeserializationError.
def mailer_class
if mailer = Array(@serialized_arguments).first || Array(arguments).first
mailer.constantize
end
end

def handle_exception_with_mailer_class(exception)
if klass = mailer_class
klass.handle_exception exception
else
raise exception
end
end
end
end
10 changes: 9 additions & 1 deletion actionmailer/lib/action_mailer/message_delivery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,18 @@ def enqueue_delivery(delivery_method, options = {})
"#deliver_later, 2. only touch the message *within your mailer " \
"method*, or 3. use a custom Active Job instead of #deliver_later."
else
args = @mailer_class.name, @action.to_s, delivery_method.to_s, nil, *@args
job = @mailer_class.delivery_job
args = arguments_for(job, delivery_method)
job.set(options).perform_later(*args)
end
end

def arguments_for(delivery_job, delivery_method)
if delivery_job <= MailDeliveryJob
[@mailer_class.name, @action.to_s, delivery_method.to_s, args: @args]
else
[@mailer_class.name, @action.to_s, delivery_method.to_s, *@args]
end
end
end
end
18 changes: 16 additions & 2 deletions actionmailer/lib/action_mailer/parameterized.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,12 @@ def respond_to_missing?(method, include_all = false)
end
end

class DeliveryJob < ActionMailer::DeliveryJob # :nodoc:
def perform(mailer, mail_method, delivery_method, params, *args)
mailer.constantize.with(params).public_send(mail_method, *args).send(delivery_method)
end
end

class MessageDelivery < ActionMailer::MessageDelivery # :nodoc:
def initialize(mailer_class, action, params, *args)
super(mailer_class, action, *args)
Expand All @@ -139,11 +145,19 @@ def enqueue_delivery(delivery_method, options = {})
if processed?
super
else
args = @mailer_class.name, @action.to_s, delivery_method.to_s, @params, *@args
job = @mailer_class.delivery_job
job = @mailer_class.delivery_job
args = arguments_for(job, delivery_method)
job.set(options).perform_later(*args)
end
end

def arguments_for(delivery_job, delivery_method)
if delivery_job <= MailDeliveryJob
[@mailer_class.name, @action.to_s, delivery_method.to_s, params: @params, args: @args]
else
[@mailer_class.name, @action.to_s, delivery_method.to_s, @params, *@args]
end
end
end
end
end
4 changes: 2 additions & 2 deletions actionmailer/lib/action_mailer/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,9 +125,9 @@ def assert_enqueued_emails(number, &block)
# end
def assert_enqueued_email_with(mailer, method, args: nil, queue: "mailers", &block)
args = if args.is_a?(Hash)
[mailer.to_s, method.to_s, "deliver_now", args]
[mailer.to_s, method.to_s, "deliver_now", params: args, args: []]
else
[mailer.to_s, method.to_s, "deliver_now", nil, *args]
[mailer.to_s, method.to_s, "deliver_now", args: Array(args)]
end
assert_enqueued_with(job: mailer.delivery_job, args: args, queue: queue, &block)
end
Expand Down
86 changes: 86 additions & 0 deletions actionmailer/test/legacy_delivery_job_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

require "abstract_unit"
require "active_job"
require "mailers/params_mailer"
require "mailers/delayed_mailer"

class LegacyDeliveryJobTest < ActiveSupport::TestCase
include ActiveJob::TestHelper

class LegacyDeliveryJob < ActionMailer::DeliveryJob
end

class LegacyParmeterizedDeliveryJob < ActionMailer::Parameterized::DeliveryJob
end

setup do
@previous_logger = ActiveJob::Base.logger
ActiveJob::Base.logger = Logger.new(nil)

@previous_delivery_method = ActionMailer::Base.delivery_method
ActionMailer::Base.delivery_method = :test

@previous_deliver_later_queue_name = ActionMailer::Base.deliver_later_queue_name
ActionMailer::Base.deliver_later_queue_name = :test_queue
end

teardown do
ActiveJob::Base.logger = @previous_logger
ParamsMailer.deliveries.clear

ActionMailer::Base.delivery_method = @previous_delivery_method
ActionMailer::Base.deliver_later_queue_name = @previous_deliver_later_queue_name
end

test "should send parameterized mail correctly" do
mail = ParamsMailer.with(inviter: "[email protected]", invitee: "[email protected]").invitation
args = [
"ParamsMailer",
"invitation",
"deliver_now",
{ inviter: "[email protected]", invitee: "[email protected]" },
]

with_delivery_job(LegacyParmeterizedDeliveryJob) do
assert_deprecated do
assert_performed_with(job: LegacyParmeterizedDeliveryJob, args: args) do
mail.deliver_later
end
end
end
end

test "should send mail correctly" do
mail = DelayedMailer.test_message(1, 2, 3)
args = [
"DelayedMailer",
"test_message",
"deliver_now",
1,
2,
3,
]

with_delivery_job(LegacyDeliveryJob) do
assert_deprecated do
assert_performed_with(job: LegacyDeliveryJob, args: args) do
mail.deliver_later
end
end
end
end

private

def with_delivery_job(job)
old_params_delivery_job = ParamsMailer.delivery_job
old_regular_delivery_job = DelayedMailer.delivery_job
ParamsMailer.delivery_job = job
DelayedMailer.delivery_job = job
yield
ensure
ParamsMailer.delivery_job = old_params_delivery_job
DelayedMailer.delivery_job = old_regular_delivery_job
end
end
16 changes: 8 additions & 8 deletions actionmailer/test/message_delivery_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,34 +64,34 @@ def test_should_enqueue_and_run_correctly_in_activejob
end

test "should enqueue the email with :deliver_now delivery method" do
assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3]) do
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]]) do
@mail.deliver_later
end
end

test "should enqueue the email with :deliver_now! delivery method" do
assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now!", nil, 1, 2, 3]) do
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now!", args: [1, 2, 3]]) do
@mail.deliver_later!
end
end

test "should enqueue a delivery with a delay" do
travel_to Time.new(2004, 11, 24, 01, 04, 44) do
assert_performed_with(job: ActionMailer::DeliveryJob, at: Time.current + 10.minutes, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3]) do
assert_performed_with(job: ActionMailer::MailDeliveryJob, at: Time.current + 10.minutes, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]]) do
@mail.deliver_later wait: 10.minutes
end
end
end

test "should enqueue a delivery at a specific time" do
later_time = Time.current + 1.hour
assert_performed_with(job: ActionMailer::DeliveryJob, at: later_time, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3]) do
assert_performed_with(job: ActionMailer::MailDeliveryJob, at: later_time, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]]) do
@mail.deliver_later wait_until: later_time
end
end

test "should enqueue the job on the correct queue" do
assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3], queue: "test_queue") do
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]], queue: "test_queue") do
@mail.deliver_later
end
end
Expand All @@ -100,17 +100,17 @@ def test_should_enqueue_and_run_correctly_in_activejob
old_delivery_job = DelayedMailer.delivery_job
DelayedMailer.delivery_job = DummyJob

assert_performed_with(job: DummyJob, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3]) do
assert_performed_with(job: DummyJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]]) do
@mail.deliver_later
end

DelayedMailer.delivery_job = old_delivery_job
end

class DummyJob < ActionMailer::DeliveryJob; end
class DummyJob < ActionMailer::MailDeliveryJob; end

test "can override the queue when enqueuing mail" do
assert_performed_with(job: ActionMailer::DeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", nil, 1, 2, 3], queue: "another_queue") do
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]], queue: "another_queue") do
@mail.deliver_later(queue: :another_queue)
end
end
Expand Down
10 changes: 6 additions & 4 deletions actionmailer/test/parameterized_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
class ParameterizedTest < ActiveSupport::TestCase
include ActiveJob::TestHelper

class DummyDeliveryJob < ActionMailer::DeliveryJob
class DummyDeliveryJob < ActionMailer::MailDeliveryJob
end

setup do
Expand Down Expand Up @@ -42,9 +42,10 @@ class DummyDeliveryJob < ActionMailer::DeliveryJob
"ParamsMailer",
"invitation",
"deliver_now",
{ inviter: "[email protected]", invitee: "[email protected]" },
params: { inviter: "[email protected]", invitee: "[email protected]" },
args: [],
]
assert_performed_with(job: ActionMailer::DeliveryJob, args: args) do
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: args) do
@mail.deliver_later
end
end
Expand All @@ -68,7 +69,8 @@ class DummyDeliveryJob < ActionMailer::DeliveryJob
"ParamsMailer",
"invitation",
"deliver_now",
{ inviter: "[email protected]", invitee: "[email protected]" },
params: { inviter: "[email protected]", invitee: "[email protected]" },
args: [],
]

with_delivery_job DummyDeliveryJob do
Expand Down
2 changes: 1 addition & 1 deletion actionmailer/test/test_helper_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_parameter_args
end
end

class CustomDeliveryJob < ActionMailer::DeliveryJob
class CustomDeliveryJob < ActionMailer::MailDeliveryJob
end

class CustomDeliveryMailer < TestHelperMailer
Expand Down