Allow mailer classes to customize the deliver_later queue name
The `deliver_later_queue_name` is already configurable on ActionMailer::Base, however the value is inherited by all subclasses. Use a class-inheritable attribute instead, so that subclasses can override. Refs: - https://github.com/rails/rails/pull/18587#issuecomment-324975192
This commit is contained in:
parent
26e21fc854
commit
fa17c9ac99
@ -1,3 +1,17 @@
|
||||
* The `deliver_later_queue_name` used by the default mailer job can now be
|
||||
configured on a per-mailer basis. Previously this was only configurable
|
||||
for all mailers via `ActionMailer::Base`.
|
||||
|
||||
Example:
|
||||
|
||||
```ruby
|
||||
class EventsMailer < ApplicationMailer
|
||||
self.deliver_later_queue_name = :throttled_mailer
|
||||
end
|
||||
```
|
||||
|
||||
*Jeffrey Hardy*
|
||||
|
||||
* Email previews now include an expandable section to show all headers.
|
||||
|
||||
Headers like `Message-ID` for threading or email service provider specific
|
||||
|
@ -53,6 +53,7 @@ module ActionMailer
|
||||
autoload :TestHelper
|
||||
autoload :MessageDelivery
|
||||
autoload :MailDeliveryJob
|
||||
autoload :QueuedDelivery
|
||||
|
||||
def self.eager_load!
|
||||
super
|
||||
|
@ -460,12 +460,14 @@ module ActionMailer
|
||||
# * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with
|
||||
# <tt>delivery_method :test</tt>. Most useful for unit and functional testing.
|
||||
#
|
||||
# * <tt>delivery_job</tt> - The job class used with <tt>deliver_later</tt>. Defaults to
|
||||
# +ActionMailer::MailDeliveryJob+.
|
||||
# * <tt>delivery_job</tt> - The job class used with <tt>deliver_later</tt>. Mailers can set this to use a
|
||||
# custom delivery job. Defaults to +ActionMailer::MailDeliveryJob+.
|
||||
#
|
||||
# * <tt>deliver_later_queue_name</tt> - The name of the queue used with <tt>deliver_later</tt>.
|
||||
# * <tt>deliver_later_queue_name</tt> - The queue name used by <tt>deliver_later</tt> with the default
|
||||
# <tt>delivery_job</tt>. Mailers can set this to use a custom queue. Defaults to <tt>:mailers</tt>.
|
||||
class Base < AbstractController::Base
|
||||
include DeliveryMethods
|
||||
include QueuedDelivery
|
||||
include Rescuable
|
||||
include Parameterized
|
||||
include Previews
|
||||
@ -487,7 +489,6 @@ class Base < AbstractController::Base
|
||||
|
||||
helper ActionMailer::MailHelper
|
||||
|
||||
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
|
||||
class_attribute :default_params, default: {
|
||||
mime_version: "1.0",
|
||||
charset: "UTF-8",
|
||||
|
@ -12,7 +12,6 @@ module DeliveryMethods
|
||||
# Do not make this inheritable, because we always want it to propagate
|
||||
cattr_accessor :raise_delivery_errors, default: true
|
||||
cattr_accessor :perform_deliveries, default: true
|
||||
cattr_accessor :deliver_later_queue_name, default: :mailers
|
||||
|
||||
class_attribute :delivery_methods, default: {}.freeze
|
||||
class_attribute :delivery_method, default: :smtp
|
||||
|
@ -9,7 +9,10 @@ module ActionMailer
|
||||
#
|
||||
# Exceptions are rescued and handled by the mailer class.
|
||||
class MailDeliveryJob < ActiveJob::Base # :nodoc:
|
||||
queue_as { ActionMailer::Base.deliver_later_queue_name }
|
||||
queue_as do
|
||||
mailer_class = arguments.first.constantize
|
||||
mailer_class.deliver_later_queue_name
|
||||
end
|
||||
|
||||
rescue_from StandardError, with: :handle_exception_with_mailer_class
|
||||
|
||||
|
@ -62,9 +62,10 @@ def processed?
|
||||
# * <tt>:queue</tt> - Enqueue the email on the specified queue
|
||||
# * <tt>:priority</tt> - Enqueues the email with the specified priority
|
||||
#
|
||||
# By default, the email will be enqueued using <tt>ActionMailer::MailDeliveryJob</tt>. Each
|
||||
# ActionMailer::Base class can specify the job to use by setting the class variable
|
||||
# +delivery_job+.
|
||||
# By default, the email will be enqueued using <tt>ActionMailer::MailDeliveryJob</tt> on
|
||||
# the +:mailers+ queue. Mailer classes can customize the queue name used for the default
|
||||
# job by assigning a +deliver_later_queue_name+ class variable, or provide a custom job
|
||||
# by assigning a +delivery_job+. When a custom job is used, it controls the queue name.
|
||||
#
|
||||
# class AccountRegistrationMailer < ApplicationMailer
|
||||
# self.delivery_job = RegistrationDeliveryJob
|
||||
@ -88,9 +89,10 @@ def deliver_later!(options = {})
|
||||
# * <tt>:queue</tt> - Enqueue the email on the specified queue.
|
||||
# * <tt>:priority</tt> - Enqueues the email with the specified priority
|
||||
#
|
||||
# By default, the email will be enqueued using <tt>ActionMailer::MailDeliveryJob</tt>. Each
|
||||
# ActionMailer::Base class can specify the job to use by setting the class variable
|
||||
# +delivery_job+.
|
||||
# By default, the email will be enqueued using <tt>ActionMailer::MailDeliveryJob</tt> on
|
||||
# the +:mailers+ queue. Mailer classes can customize the queue name used for the default
|
||||
# job by assigning a +deliver_later_queue_name+ class variable, or provide a custom job
|
||||
# by assigning a +delivery_job+. When a custom job is used, it controls the queue name.
|
||||
#
|
||||
# class AccountRegistrationMailer < ApplicationMailer
|
||||
# self.delivery_job = RegistrationDeliveryJob
|
||||
|
12
actionmailer/lib/action_mailer/queued_delivery.rb
Normal file
12
actionmailer/lib/action_mailer/queued_delivery.rb
Normal file
@ -0,0 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module ActionMailer
|
||||
module QueuedDelivery
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
|
||||
class_attribute :deliver_later_queue_name, default: :mailers
|
||||
end
|
||||
end
|
||||
end
|
@ -170,11 +170,14 @@ def assert_enqueued_emails(number, &block)
|
||||
# ContactMailer.with(email: 'user@example.com').welcome.deliver_later
|
||||
# end
|
||||
# end
|
||||
def assert_enqueued_email_with(mailer, method, params: nil, args: nil, queue: ActionMailer::Base.deliver_later_queue_name || "default", &block)
|
||||
def assert_enqueued_email_with(mailer, method, params: nil, args: nil, queue: nil, &block)
|
||||
if mailer.is_a? ActionMailer::Parameterized::Mailer
|
||||
params = mailer.instance_variable_get(:@params)
|
||||
mailer = mailer.instance_variable_get(:@mailer)
|
||||
end
|
||||
|
||||
queue ||= mailer.deliver_later_queue_name || ActiveJob::Base.default_queue_name
|
||||
|
||||
args = if args.is_a?(Hash)
|
||||
[mailer.to_s, method.to_s, "deliver_now", params: args, args: []]
|
||||
elsif params.present?
|
||||
@ -182,6 +185,7 @@ def assert_enqueued_email_with(mailer, method, params: nil, args: nil, queue: Ac
|
||||
else
|
||||
[mailer.to_s, method.to_s, "deliver_now", args: Array(args)]
|
||||
end
|
||||
|
||||
assert_enqueued_with(job: mailer.delivery_job, args: args, queue: queue.to_s, &block)
|
||||
end
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
class DelayedMailerError < StandardError; end
|
||||
|
||||
class DelayedMailer < ActionMailer::Base
|
||||
self.deliver_later_queue_name = :delayed_mailers
|
||||
|
||||
cattr_accessor :last_error
|
||||
cattr_accessor :last_rescue_from_instance
|
||||
|
||||
|
@ -10,10 +10,10 @@ class MessageDeliveryTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@previous_logger = ActiveJob::Base.logger
|
||||
@previous_delivery_method = ActionMailer::Base.delivery_method
|
||||
@previous_deliver_later_queue_name = ActionMailer::Base.deliver_later_queue_name
|
||||
ActionMailer::Base.deliver_later_queue_name = :test_queue
|
||||
ActionMailer::Base.delivery_method = :test
|
||||
|
||||
ActiveJob::Base.logger = Logger.new(nil)
|
||||
ActionMailer::Base.delivery_method = :test
|
||||
|
||||
ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true
|
||||
ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true
|
||||
|
||||
@ -28,7 +28,6 @@ class MessageDeliveryTest < ActiveSupport::TestCase
|
||||
|
||||
ActiveJob::Base.logger = @previous_logger
|
||||
ActionMailer::Base.delivery_method = @previous_delivery_method
|
||||
ActionMailer::Base.deliver_later_queue_name = @previous_deliver_later_queue_name
|
||||
|
||||
DelayedMailer.last_error = nil
|
||||
DelayedMailer.last_rescue_from_instance = nil
|
||||
@ -75,7 +74,7 @@ def test_should_enqueue_and_run_correctly_in_activejob
|
||||
end
|
||||
end
|
||||
|
||||
test "should enqueue a delivery with a delay" do
|
||||
test "should enqueue delivery with a delay" do
|
||||
travel_to Time.new(2004, 11, 24, 1, 4, 44) 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
|
||||
@ -83,25 +82,25 @@ def test_should_enqueue_and_run_correctly_in_activejob
|
||||
end
|
||||
end
|
||||
|
||||
test "should enqueue a delivery with a priority" do
|
||||
test "should enqueue delivery with a priority" do
|
||||
job = @mail.deliver_later priority: 10
|
||||
assert_equal 10, job.priority
|
||||
end
|
||||
|
||||
test "should enqueue a delivery at a specific time" do
|
||||
test "should enqueue delivery at a specific time" do
|
||||
later_time = Time.current + 1.hour
|
||||
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::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]], queue: "test_queue") do
|
||||
test "should enqueue delivery on the correct queue" do
|
||||
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: [1, 2, 3]], queue: "delayed_mailers") do
|
||||
@mail.deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
test "should enqueue the job with the correct delivery job" do
|
||||
test "should enqueue delivery with the correct job" do
|
||||
old_delivery_job = DelayedMailer.delivery_job
|
||||
DelayedMailer.delivery_job = DummyJob
|
||||
|
||||
@ -114,12 +113,26 @@ def test_should_enqueue_and_run_correctly_in_activejob
|
||||
|
||||
class DummyJob < ActionMailer::MailDeliveryJob; end
|
||||
|
||||
test "can override the queue when enqueuing mail" do
|
||||
test "delivery queue can be overridden when enqueuing mail" 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
|
||||
|
||||
test "delivery queue can be overridden in subclasses" do
|
||||
previous_queue_name = DelayedMailer.deliver_later_queue_name
|
||||
DelayedMailer.deliver_later_queue_name = :throttled_mailers
|
||||
|
||||
assert_equal :throttled_mailers, DelayedMailer.deliver_later_queue_name
|
||||
assert_equal :mailers, ActionMailer::Base.deliver_later_queue_name
|
||||
|
||||
assert_performed_with(job: ActionMailer::MailDeliveryJob, args: ["DelayedMailer", "test_message", "deliver_now", args: []], queue: "throttled_mailers") do
|
||||
DelayedMailer.test_message.deliver_later
|
||||
end
|
||||
ensure
|
||||
DelayedMailer.deliver_later_queue_name = previous_queue_name
|
||||
end
|
||||
|
||||
test "deliver_later after accessing the message is disallowed" do
|
||||
@mail.message # Load the message, which calls the mailer method.
|
||||
|
||||
|
@ -17,18 +17,13 @@ class DummyDeliveryJob < ActionMailer::MailDeliveryJob
|
||||
@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
|
||||
|
||||
@mail = ParamsMailer.with(inviter: "david@basecamp.com", invitee: "jason@basecamp.com").invitation
|
||||
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 "parameterized headers" do
|
||||
|
@ -38,6 +38,10 @@ class CustomDeliveryMailer < TestHelperMailer
|
||||
self.delivery_job = CustomDeliveryJob
|
||||
end
|
||||
|
||||
class CustomQueueMailer < TestHelperMailer
|
||||
self.deliver_later_queue_name = :custom_queue
|
||||
end
|
||||
|
||||
class TestHelperMailerTest < ActionMailer::TestCase
|
||||
include ActiveSupport::Testing::Stream
|
||||
|
||||
@ -371,6 +375,22 @@ def test_assert_enqueued_email_with_when_queue_arg_is_symbol
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_enqueued_email_with_when_mailer_has_custom_deliver_later_queue
|
||||
assert_nothing_raised do
|
||||
assert_enqueued_email_with CustomQueueMailer, :test do
|
||||
silence_stream($stdout) do
|
||||
CustomQueueMailer.test.deliver_later
|
||||
end
|
||||
end
|
||||
|
||||
assert_enqueued_email_with CustomQueueMailer, :test, queue: :custom_queue do
|
||||
silence_stream($stdout) do
|
||||
CustomQueueMailer.test.deliver_later
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_assert_enqueued_email_with_when_mailer_has_custom_delivery_job
|
||||
assert_nothing_raised do
|
||||
assert_enqueued_email_with CustomDeliveryMailer, :test do
|
||||
|
@ -818,7 +818,7 @@ files (environment.rb, production.rb, etc...)
|
||||
|`perform_deliveries`|Determines whether deliveries are actually carried out when the `deliver` method is invoked on the Mail message. By default they are, but this can be turned off to help functional testing. If this value is `false`, `deliveries` array will not be populated even if `delivery_method` is `:test`.|
|
||||
|`deliveries`|Keeps an array of all the emails sent out through the Action Mailer with delivery_method :test. Most useful for unit and functional testing.|
|
||||
|`delivery_job`|The job class used with `deliver_later`. Defaults to `ActionMailer::MailDeliveryJob`.|
|
||||
|`deliver_later_queue_name`|The name of the queue used with `deliver_later`.|
|
||||
|`deliver_later_queue_name`|The name of the queue used with the default `delivery_job`. Defaults to `:mailers|
|
||||
|`default_options`|Allows you to set default values for the `mail` method options (`:from`, `:reply_to`, etc.).|
|
||||
|
||||
For a complete writeup of possible configurations see the
|
||||
|
@ -2112,9 +2112,18 @@ Enable or disable mailer previews. By default this is `true` in development.
|
||||
config.action_mailer.show_previews = false
|
||||
```
|
||||
|
||||
#### `config.action_mailer.perform_caching`
|
||||
|
||||
Specifies whether the mailer templates should perform fragment caching or not. If it's not specified, the default will be `true`.
|
||||
|
||||
#### `config.action_mailer.deliver_later_queue_name`
|
||||
|
||||
Specifies the Active Job queue to use for delivery jobs. When this option is set to `nil`, delivery jobs are sent to the default Active Job queue (see `config.active_job.default_queue_name`). Make sure that your Active Job adapter is also configured to process the specified queue, otherwise delivery jobs may be silently ignored.
|
||||
Specifies the Active Job queue to use for the default delivery job (see `config.action_mailer.delivery_job`). When this option is set to `nil`, delivery jobs are sent to the default Active Job queue (see `config.active_job.default_queue_name`).
|
||||
|
||||
Mailer classes can override this to use a different queue. Note that this only applies when using the default delivery job. If your mailer is using a custom
|
||||
job, its queue will be used.
|
||||
|
||||
Ensure that your Active Job adapter is also configured to process the specified queue, otherwise delivery jobs may be silently ignored.
|
||||
|
||||
The default value depends on the `config.load_defaults` target version:
|
||||
|
||||
@ -2123,10 +2132,6 @@ The default value depends on the `config.load_defaults` target version:
|
||||
| (original) | `:mailers` |
|
||||
| 6.1 | `nil` |
|
||||
|
||||
#### `config.action_mailer.perform_caching`
|
||||
|
||||
Specifies whether the mailer templates should perform fragment caching or not. If it's not specified, the default will be `true`.
|
||||
|
||||
#### `config.action_mailer.delivery_job`
|
||||
|
||||
Specifies delivery job for mail.
|
||||
|
@ -1281,7 +1281,7 @@ def index
|
||||
require "mail"
|
||||
_ = ActionMailer::Base
|
||||
|
||||
assert_equal "test_default", ActionMailer::Base.class_variable_get(:@@deliver_later_queue_name)
|
||||
assert_equal "test_default", ActionMailer::Base.deliver_later_queue_name
|
||||
end
|
||||
|
||||
test "ActionMailer::DeliveryJob queue name is :mailers without the Rails defaults" do
|
||||
@ -1292,7 +1292,7 @@ def index
|
||||
require "mail"
|
||||
_ = ActionMailer::Base
|
||||
|
||||
assert_equal :mailers, ActionMailer::Base.class_variable_get(:@@deliver_later_queue_name)
|
||||
assert_equal :mailers, ActionMailer::Base.deliver_later_queue_name
|
||||
end
|
||||
|
||||
test "ActionMailer::DeliveryJob queue name is nil by default in 6.1" do
|
||||
@ -1304,7 +1304,7 @@ def index
|
||||
require "mail"
|
||||
_ = ActionMailer::Base
|
||||
|
||||
assert_nil ActionMailer::Base.class_variable_get(:@@deliver_later_queue_name)
|
||||
assert_nil ActionMailer::Base.deliver_later_queue_name
|
||||
end
|
||||
|
||||
test "valid timezone is setup correctly" do
|
||||
|
Loading…
Reference in New Issue
Block a user