actionmailer 7.0.8 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionmailer might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +99 -57
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/action_mailer/base.rb +58 -46
- data/lib/action_mailer/callbacks.rb +31 -0
- data/lib/action_mailer/delivery_methods.rb +5 -3
- data/lib/action_mailer/deprecator.rb +7 -0
- data/lib/action_mailer/form_builder.rb +37 -0
- data/lib/action_mailer/gem_version.rb +4 -4
- data/lib/action_mailer/inline_preview_interceptor.rb +2 -0
- data/lib/action_mailer/log_subscriber.rb +7 -2
- data/lib/action_mailer/mail_delivery_job.rb +7 -2
- data/lib/action_mailer/mail_helper.rb +2 -0
- data/lib/action_mailer/message_delivery.rb +20 -12
- data/lib/action_mailer/parameterized.rb +7 -1
- data/lib/action_mailer/preview.rb +32 -8
- data/lib/action_mailer/queued_delivery.rb +12 -0
- data/lib/action_mailer/railtie.rb +11 -16
- data/lib/action_mailer/rescuable.rb +2 -0
- data/lib/action_mailer/test_case.rb +9 -4
- data/lib/action_mailer/test_helper.rb +134 -11
- data/lib/action_mailer/version.rb +1 -1
- data/lib/action_mailer.rb +11 -2
- data/lib/rails/generators/mailer/USAGE +12 -8
- metadata +20 -16
@@ -3,6 +3,8 @@
|
|
3
3
|
require "tmpdir"
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
+
# = Action Mailer \DeliveryMethods
|
7
|
+
#
|
6
8
|
# This module handles everything related to mail delivery, from registering
|
7
9
|
# new delivery methods to configuring the mail object to be sent.
|
8
10
|
module DeliveryMethods
|
@@ -12,7 +14,6 @@ module ActionMailer
|
|
12
14
|
# Do not make this inheritable, because we always want it to propagate
|
13
15
|
cattr_accessor :raise_delivery_errors, default: true
|
14
16
|
cattr_accessor :perform_deliveries, default: true
|
15
|
-
cattr_accessor :deliver_later_queue_name, default: :mailers
|
16
17
|
|
17
18
|
class_attribute :delivery_methods, default: {}.freeze
|
18
19
|
class_attribute :delivery_method, default: :smtp
|
@@ -31,7 +32,8 @@ module ActionMailer
|
|
31
32
|
|
32
33
|
add_delivery_method :sendmail, Mail::Sendmail,
|
33
34
|
location: "/usr/sbin/sendmail",
|
34
|
-
|
35
|
+
# See breaking change in the mail gem - https://github.com/mikel/mail/commit/7e1196bd29815a0901d7290c82a332c0959b163a
|
36
|
+
arguments: Gem::Version.new(Mail::VERSION.version) >= Gem::Version.new("2.8.0") ? %w[-i] : "-i"
|
35
37
|
|
36
38
|
add_delivery_method :test, Mail::TestMailer
|
37
39
|
end
|
@@ -46,7 +48,7 @@ module ActionMailer
|
|
46
48
|
#
|
47
49
|
# add_delivery_method :sendmail, Mail::Sendmail,
|
48
50
|
# location: '/usr/sbin/sendmail',
|
49
|
-
# arguments:
|
51
|
+
# arguments: %w[ -i ]
|
50
52
|
def add_delivery_method(symbol, klass, default_options = {})
|
51
53
|
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
|
52
54
|
public_send(:"#{symbol}_settings=", default_options)
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionMailer
|
4
|
+
# = Action Mailer Form Builder
|
5
|
+
#
|
6
|
+
# Override the default form builder for all views rendered by this
|
7
|
+
# mailer and any of its descendants. Accepts a subclass of
|
8
|
+
# ActionView::Helpers::FormBuilder.
|
9
|
+
#
|
10
|
+
# While emails typically will not include forms, this can be used
|
11
|
+
# by views that are shared between controllers and mailers.
|
12
|
+
#
|
13
|
+
# For more information, see +ActionController::FormBuilder+.
|
14
|
+
module FormBuilder
|
15
|
+
extend ActiveSupport::Concern
|
16
|
+
|
17
|
+
included do
|
18
|
+
class_attribute :_default_form_builder, instance_accessor: false
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
# Set the form builder to be used as the default for all forms
|
23
|
+
# in the views rendered by this mailer and its subclasses.
|
24
|
+
#
|
25
|
+
# ==== Parameters
|
26
|
+
# * <tt>builder</tt> - Default form builder, an instance of ActionView::Helpers::FormBuilder
|
27
|
+
def default_form_builder(builder)
|
28
|
+
self._default_form_builder = builder
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Default form builder for the mailer
|
33
|
+
def default_form_builder
|
34
|
+
self.class._default_form_builder
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionMailer
|
4
|
-
# Returns the currently loaded version of Action Mailer as a
|
4
|
+
# Returns the currently loaded version of Action Mailer as a +Gem::Version+.
|
5
5
|
def self.gem_version
|
6
6
|
Gem::Version.new VERSION::STRING
|
7
7
|
end
|
8
8
|
|
9
9
|
module VERSION
|
10
10
|
MAJOR = 7
|
11
|
-
MINOR =
|
12
|
-
TINY =
|
13
|
-
PRE =
|
11
|
+
MINOR = 1
|
12
|
+
TINY = 3
|
13
|
+
PRE = "4"
|
14
14
|
|
15
15
|
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
|
16
16
|
end
|
@@ -3,6 +3,8 @@
|
|
3
3
|
require "base64"
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
+
# = Action Mailer \InlinePreviewInterceptor
|
7
|
+
#
|
6
8
|
# Implements a mailer preview interceptor that converts image tag src attributes
|
7
9
|
# that use inline cid: style URLs to data: style URLs so that they are visible
|
8
10
|
# when previewing an HTML email in a web browser.
|
@@ -3,14 +3,17 @@
|
|
3
3
|
require "active_support/log_subscriber"
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
+
# = Action Mailer \LogSubscriber
|
7
|
+
#
|
6
8
|
# Implements the ActiveSupport::LogSubscriber for logging notifications when
|
7
9
|
# email is delivered or received.
|
8
10
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
9
11
|
# An email was delivered.
|
10
12
|
def deliver(event)
|
11
13
|
info do
|
12
|
-
|
13
|
-
|
14
|
+
if exception = event.payload[:exception_object]
|
15
|
+
"Failed delivery of mail #{event.payload[:message_id]} error_class=#{exception.class} error_message=#{exception.message.inspect}"
|
16
|
+
elsif event.payload[:perform_deliveries]
|
14
17
|
"Delivered mail #{event.payload[:message_id]} (#{event.duration.round(1)}ms)"
|
15
18
|
else
|
16
19
|
"Skipped delivery of mail #{event.payload[:message_id]} as `perform_deliveries` is false"
|
@@ -19,6 +22,7 @@ module ActionMailer
|
|
19
22
|
|
20
23
|
debug { event.payload[:mail] }
|
21
24
|
end
|
25
|
+
subscribe_log_level :deliver, :debug
|
22
26
|
|
23
27
|
# An email was generated.
|
24
28
|
def process(event)
|
@@ -28,6 +32,7 @@ module ActionMailer
|
|
28
32
|
"#{mailer}##{action}: processed outbound mail in #{event.duration.round(1)}ms"
|
29
33
|
end
|
30
34
|
end
|
35
|
+
subscribe_log_level :process, :debug
|
31
36
|
|
32
37
|
# Use the logger configured for ActionMailer::Base.
|
33
38
|
def logger
|
@@ -3,13 +3,18 @@
|
|
3
3
|
require "active_job"
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
-
#
|
6
|
+
# = Action Mailer \MailDeliveryJob
|
7
|
+
#
|
8
|
+
# The +ActionMailer::MailDeliveryJob+ class is used when you
|
7
9
|
# want to send emails outside of the request-response cycle. It supports
|
8
10
|
# sending either parameterized or normal mail.
|
9
11
|
#
|
10
12
|
# Exceptions are rescued and handled by the mailer class.
|
11
13
|
class MailDeliveryJob < ActiveJob::Base # :nodoc:
|
12
|
-
queue_as
|
14
|
+
queue_as do
|
15
|
+
mailer_class = arguments.first.constantize
|
16
|
+
mailer_class.deliver_later_queue_name
|
17
|
+
end
|
13
18
|
|
14
19
|
rescue_from StandardError, with: :handle_exception_with_mailer_class
|
15
20
|
|
@@ -3,11 +3,13 @@
|
|
3
3
|
require "delegate"
|
4
4
|
|
5
5
|
module ActionMailer
|
6
|
-
#
|
6
|
+
# = Action Mailer \MessageDelivery
|
7
|
+
#
|
8
|
+
# The +ActionMailer::MessageDelivery+ class is used by
|
7
9
|
# ActionMailer::Base when creating a new mailer.
|
8
10
|
# <tt>MessageDelivery</tt> is a wrapper (+Delegator+ subclass) around a lazy
|
9
|
-
# created
|
10
|
-
#
|
11
|
+
# created +Mail::Message+. You can get direct access to the
|
12
|
+
# +Mail::Message+, deliver the email or schedule the email to be sent
|
11
13
|
# through Active Job.
|
12
14
|
#
|
13
15
|
# Notifier.welcome(User.first) # an ActionMailer::MessageDelivery object
|
@@ -62,9 +64,10 @@ module ActionMailer
|
|
62
64
|
# * <tt>:queue</tt> - Enqueue the email on the specified queue
|
63
65
|
# * <tt>:priority</tt> - Enqueues the email with the specified priority
|
64
66
|
#
|
65
|
-
# By default, the email will be enqueued using
|
66
|
-
#
|
67
|
-
# +
|
67
|
+
# By default, the email will be enqueued using ActionMailer::MailDeliveryJob on
|
68
|
+
# the default queue. Mailer classes can customize the queue name used for the default
|
69
|
+
# job by assigning a +deliver_later_queue_name+ class variable, or provide a custom job
|
70
|
+
# by assigning a +delivery_job+. When a custom job is used, it controls the queue name.
|
68
71
|
#
|
69
72
|
# class AccountRegistrationMailer < ApplicationMailer
|
70
73
|
# self.delivery_job = RegistrationDeliveryJob
|
@@ -88,9 +91,10 @@ module ActionMailer
|
|
88
91
|
# * <tt>:queue</tt> - Enqueue the email on the specified queue.
|
89
92
|
# * <tt>:priority</tt> - Enqueues the email with the specified priority
|
90
93
|
#
|
91
|
-
# By default, the email will be enqueued using
|
92
|
-
#
|
93
|
-
# +
|
94
|
+
# By default, the email will be enqueued using ActionMailer::MailDeliveryJob on
|
95
|
+
# the default queue. Mailer classes can customize the queue name used for the default
|
96
|
+
# job by assigning a +deliver_later_queue_name+ class variable, or provide a custom job
|
97
|
+
# by assigning a +delivery_job+. When a custom job is used, it controls the queue name.
|
94
98
|
#
|
95
99
|
# class AccountRegistrationMailer < ApplicationMailer
|
96
100
|
# self.delivery_job = RegistrationDeliveryJob
|
@@ -106,7 +110,9 @@ module ActionMailer
|
|
106
110
|
#
|
107
111
|
def deliver_now!
|
108
112
|
processed_mailer.handle_exceptions do
|
109
|
-
|
113
|
+
processed_mailer.run_callbacks(:deliver) do
|
114
|
+
message.deliver!
|
115
|
+
end
|
110
116
|
end
|
111
117
|
end
|
112
118
|
|
@@ -116,13 +122,15 @@ module ActionMailer
|
|
116
122
|
#
|
117
123
|
def deliver_now
|
118
124
|
processed_mailer.handle_exceptions do
|
119
|
-
|
125
|
+
processed_mailer.run_callbacks(:deliver) do
|
126
|
+
message.deliver
|
127
|
+
end
|
120
128
|
end
|
121
129
|
end
|
122
130
|
|
123
131
|
private
|
124
132
|
# Returns the processed Mailer instance. We keep this instance
|
125
|
-
# on hand so we can delegate exception handling to it.
|
133
|
+
# on hand so we can run callbacks and delegate exception handling to it.
|
126
134
|
def processed_mailer
|
127
135
|
@processed_mailer ||= @mailer_class.new.tap do |mailer|
|
128
136
|
mailer.process @action, *@args
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionMailer
|
4
|
+
# = Action Mailer \Parameterized
|
5
|
+
#
|
4
6
|
# Provides the option to parameterize mailers in order to share instance variable
|
5
7
|
# setup, processing, and common headers.
|
6
8
|
#
|
@@ -88,7 +90,11 @@ module ActionMailer
|
|
88
90
|
extend ActiveSupport::Concern
|
89
91
|
|
90
92
|
included do
|
91
|
-
|
93
|
+
attr_writer :params
|
94
|
+
|
95
|
+
def params
|
96
|
+
@params ||= {}
|
97
|
+
end
|
92
98
|
end
|
93
99
|
|
94
100
|
module ClassMethods
|
@@ -7,11 +7,11 @@ module ActionMailer
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
included do
|
10
|
-
#
|
10
|
+
# Add the location of mailer previews through app configuration:
|
11
11
|
#
|
12
|
-
# config.action_mailer.
|
12
|
+
# config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
|
13
13
|
#
|
14
|
-
mattr_accessor :
|
14
|
+
mattr_accessor :preview_paths, instance_writer: false, default: []
|
15
15
|
|
16
16
|
# Enable or disable mailer previews through app configuration:
|
17
17
|
#
|
@@ -25,7 +25,31 @@ module ActionMailer
|
|
25
25
|
mattr_accessor :preview_interceptors, instance_writer: false, default: [ActionMailer::InlinePreviewInterceptor]
|
26
26
|
end
|
27
27
|
|
28
|
+
def preview_path
|
29
|
+
ActionMailer.deprecator.warn(<<-MSG.squish)
|
30
|
+
Using preview_path option is deprecated and will be removed in Rails 7.2.
|
31
|
+
Please use preview_paths instead.
|
32
|
+
MSG
|
33
|
+
self.class.preview_paths.first
|
34
|
+
end
|
35
|
+
|
28
36
|
module ClassMethods
|
37
|
+
def preview_path=(value)
|
38
|
+
ActionMailer.deprecator.warn(<<-MSG.squish)
|
39
|
+
Using preview_path= option is deprecated and will be removed in Rails 7.2.
|
40
|
+
Please use preview_paths= instead.
|
41
|
+
MSG
|
42
|
+
self.preview_paths << value
|
43
|
+
end
|
44
|
+
|
45
|
+
def preview_path
|
46
|
+
ActionMailer.deprecator.warn(<<-MSG.squish)
|
47
|
+
Using preview_path option is deprecated and will be removed in Rails 7.2.
|
48
|
+
Please use preview_paths instead.
|
49
|
+
MSG
|
50
|
+
self.preview_paths.first
|
51
|
+
end
|
52
|
+
|
29
53
|
# Register one or more Interceptors which will be called before mail is previewed.
|
30
54
|
def register_preview_interceptors(*interceptors)
|
31
55
|
interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) }
|
@@ -79,7 +103,7 @@ module ActionMailer
|
|
79
103
|
# Returns all mailer preview classes.
|
80
104
|
def all
|
81
105
|
load_previews if descendants.empty?
|
82
|
-
descendants
|
106
|
+
descendants.sort_by { |mailer| mailer.name.titleize }
|
83
107
|
end
|
84
108
|
|
85
109
|
# Returns the mail object for the given email name. The registered preview
|
@@ -119,13 +143,13 @@ module ActionMailer
|
|
119
143
|
|
120
144
|
private
|
121
145
|
def load_previews
|
122
|
-
|
123
|
-
Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file|
|
146
|
+
preview_paths.each do |preview_path|
|
147
|
+
Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file| require file }
|
124
148
|
end
|
125
149
|
end
|
126
150
|
|
127
|
-
def
|
128
|
-
Base.
|
151
|
+
def preview_paths
|
152
|
+
Base.preview_paths
|
129
153
|
end
|
130
154
|
|
131
155
|
def show_previews
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActionMailer
|
4
|
+
module QueuedDelivery
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_attribute :delivery_job, default: ::ActionMailer::MailDeliveryJob
|
9
|
+
class_attribute :deliver_later_queue_name, default: :mailers
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -8,8 +8,13 @@ require "abstract_controller/railties/routes_helpers"
|
|
8
8
|
module ActionMailer
|
9
9
|
class Railtie < Rails::Railtie # :nodoc:
|
10
10
|
config.action_mailer = ActiveSupport::OrderedOptions.new
|
11
|
+
config.action_mailer.preview_paths = []
|
11
12
|
config.eager_load_namespaces << ActionMailer
|
12
13
|
|
14
|
+
initializer "action_mailer.deprecator", before: :load_environment_config do |app|
|
15
|
+
app.deprecators[:action_mailer] = ActionMailer.deprecator
|
16
|
+
end
|
17
|
+
|
13
18
|
initializer "action_mailer.logger" do
|
14
19
|
ActiveSupport.on_load(:action_mailer) { self.logger ||= Rails.logger }
|
15
20
|
end
|
@@ -23,10 +28,7 @@ module ActionMailer
|
|
23
28
|
options.stylesheets_dir ||= paths["public/stylesheets"].first
|
24
29
|
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
25
30
|
options.cache_store ||= Rails.cache
|
26
|
-
|
27
|
-
if options.show_previews
|
28
|
-
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
|
29
|
-
end
|
31
|
+
options.preview_paths |= ["#{Rails.root}/test/mailers/previews"]
|
30
32
|
|
31
33
|
# make sure readers methods get compiled
|
32
34
|
options.asset_host ||= app.config.asset_host
|
@@ -40,6 +42,7 @@ module ActionMailer
|
|
40
42
|
register_interceptors(options.delete(:interceptors))
|
41
43
|
register_preview_interceptors(options.delete(:preview_interceptors))
|
42
44
|
register_observers(options.delete(:observers))
|
45
|
+
self.preview_paths |= options[:preview_paths]
|
43
46
|
|
44
47
|
if delivery_job = options.delete(:delivery_job)
|
45
48
|
self.delivery_job = delivery_job.constantize
|
@@ -65,12 +68,9 @@ module ActionMailer
|
|
65
68
|
end
|
66
69
|
end
|
67
70
|
|
68
|
-
initializer "action_mailer.set_autoload_paths" do |app|
|
71
|
+
initializer "action_mailer.set_autoload_paths", before: :set_autoload_paths do |app|
|
69
72
|
options = app.config.action_mailer
|
70
|
-
|
71
|
-
if options.show_previews && options.preview_path
|
72
|
-
ActiveSupport::Dependencies.autoload_paths << options.preview_path
|
73
|
-
end
|
73
|
+
app.config.paths["test/mailers/previews"].concat(options.preview_paths)
|
74
74
|
end
|
75
75
|
|
76
76
|
initializer "action_mailer.compile_config_methods" do
|
@@ -79,18 +79,13 @@ module ActionMailer
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
initializer "action_mailer.eager_load_actions" do
|
83
|
-
ActiveSupport.on_load(:after_initialize) do
|
84
|
-
ActionMailer::Base.descendants.each(&:action_methods) if config.eager_load
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
82
|
config.after_initialize do |app|
|
89
83
|
options = app.config.action_mailer
|
90
84
|
|
91
85
|
if options.show_previews
|
92
86
|
app.routes.prepend do
|
93
|
-
get "/rails/mailers"
|
87
|
+
get "/rails/mailers" => "rails/mailers#index", internal: true
|
88
|
+
get "/rails/mailers/download/*path" => "rails/mailers#download", internal: true
|
94
89
|
get "/rails/mailers/*path" => "rails/mailers#preview", internal: true
|
95
90
|
end
|
96
91
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActionMailer # :nodoc:
|
4
|
+
# = Action Mailer \Rescuable
|
5
|
+
#
|
4
6
|
# Provides
|
5
7
|
# {rescue_from}[rdoc-ref:ActiveSupport::Rescuable::ClassMethods#rescue_from]
|
6
8
|
# for mailers. Wraps mailer action processing, mail job processing, and mail
|
@@ -74,6 +74,15 @@ module ActionMailer
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
# Reads the fixture file for the given mailer.
|
78
|
+
#
|
79
|
+
# This is useful when testing mailers by being able to write the body of
|
80
|
+
# an email inside a fixture. See the testing guide for a concrete example:
|
81
|
+
# https://guides.rubyonrails.org/testing.html#revenge-of-the-fixtures
|
82
|
+
def read_fixture(action)
|
83
|
+
IO.readlines(File.join(Rails.root, "test", "fixtures", self.class.mailer_class.name.underscore, action))
|
84
|
+
end
|
85
|
+
|
77
86
|
private
|
78
87
|
def initialize_test_deliveries
|
79
88
|
set_delivery_method :test
|
@@ -110,10 +119,6 @@ module ActionMailer
|
|
110
119
|
def encode(subject)
|
111
120
|
Mail::Encodings.q_value_encode(subject, charset)
|
112
121
|
end
|
113
|
-
|
114
|
-
def read_fixture(action)
|
115
|
-
IO.readlines(File.join(Rails.root, "test", "fixtures", self.class.mailer_class.name.underscore, action))
|
116
|
-
end
|
117
122
|
end
|
118
123
|
|
119
124
|
include Behavior
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/array/extract_options"
|
3
4
|
require "active_job"
|
4
5
|
|
5
6
|
module ActionMailer
|
@@ -33,10 +34,8 @@ module ActionMailer
|
|
33
34
|
# end
|
34
35
|
def assert_emails(number, &block)
|
35
36
|
if block_given?
|
36
|
-
|
37
|
-
|
38
|
-
new_count = ActionMailer::Base.deliveries.size
|
39
|
-
assert_equal number, new_count - original_count, "#{number} emails expected, but #{new_count - original_count} were sent"
|
37
|
+
diff = capture_emails(&block).length
|
38
|
+
assert_equal number, diff, "#{number} emails expected, but #{diff} were sent"
|
40
39
|
else
|
41
40
|
assert_equal number, ActionMailer::Base.deliveries.size
|
42
41
|
end
|
@@ -94,18 +93,50 @@ module ActionMailer
|
|
94
93
|
end
|
95
94
|
|
96
95
|
# Asserts that a specific email has been enqueued, optionally
|
97
|
-
# matching arguments.
|
96
|
+
# matching arguments and/or params.
|
98
97
|
#
|
99
98
|
# def test_email
|
100
99
|
# ContactMailer.welcome.deliver_later
|
101
100
|
# assert_enqueued_email_with ContactMailer, :welcome
|
102
101
|
# end
|
103
102
|
#
|
103
|
+
# def test_email_with_parameters
|
104
|
+
# ContactMailer.with(greeting: "Hello").welcome.deliver_later
|
105
|
+
# assert_enqueued_email_with ContactMailer, :welcome, args: { greeting: "Hello" }
|
106
|
+
# end
|
107
|
+
#
|
104
108
|
# def test_email_with_arguments
|
105
109
|
# ContactMailer.welcome("Hello", "Goodbye").deliver_later
|
106
110
|
# assert_enqueued_email_with ContactMailer, :welcome, args: ["Hello", "Goodbye"]
|
107
111
|
# end
|
108
112
|
#
|
113
|
+
# def test_email_with_named_arguments
|
114
|
+
# ContactMailer.welcome(greeting: "Hello", farewell: "Goodbye").deliver_later
|
115
|
+
# assert_enqueued_email_with ContactMailer, :welcome, args: [{ greeting: "Hello", farewell: "Goodbye" }]
|
116
|
+
# end
|
117
|
+
#
|
118
|
+
# def test_email_with_parameters_and_arguments
|
119
|
+
# ContactMailer.with(greeting: "Hello").welcome("Cheers", "Goodbye").deliver_later
|
120
|
+
# assert_enqueued_email_with ContactMailer, :welcome, params: { greeting: "Hello" }, args: ["Cheers", "Goodbye"]
|
121
|
+
# end
|
122
|
+
#
|
123
|
+
# def test_email_with_parameters_and_named_arguments
|
124
|
+
# ContactMailer.with(greeting: "Hello").welcome(farewell: "Goodbye").deliver_later
|
125
|
+
# assert_enqueued_email_with ContactMailer, :welcome, params: { greeting: "Hello" }, args: [{farewell: "Goodbye"}]
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# def test_email_with_parameterized_mailer
|
129
|
+
# ContactMailer.with(greeting: "Hello").welcome.deliver_later
|
130
|
+
# assert_enqueued_email_with ContactMailer.with(greeting: "Hello"), :welcome
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# def test_email_with_matchers
|
134
|
+
# ContactMailer.with(greeting: "Hello").welcome("Cheers", "Goodbye").deliver_later
|
135
|
+
# assert_enqueued_email_with ContactMailer, :welcome,
|
136
|
+
# params: ->(params) { /hello/i.match?(params[:greeting]) },
|
137
|
+
# args: ->(args) { /cheers/i.match?(args[0]) }
|
138
|
+
# end
|
139
|
+
#
|
109
140
|
# If a block is passed, that block should cause the specified email
|
110
141
|
# to be enqueued.
|
111
142
|
#
|
@@ -123,13 +154,43 @@ module ActionMailer
|
|
123
154
|
# ContactMailer.with(email: 'user@example.com').welcome.deliver_later
|
124
155
|
# end
|
125
156
|
# end
|
126
|
-
def assert_enqueued_email_with(mailer, method, args: nil, queue:
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
[mailer.to_s, method.to_s, "deliver_now", args: Array(args)]
|
157
|
+
def assert_enqueued_email_with(mailer, method, params: nil, args: nil, queue: nil, &block)
|
158
|
+
if mailer.is_a? ActionMailer::Parameterized::Mailer
|
159
|
+
params = mailer.instance_variable_get(:@params)
|
160
|
+
mailer = mailer.instance_variable_get(:@mailer)
|
131
161
|
end
|
132
|
-
|
162
|
+
|
163
|
+
if args.is_a?(Hash)
|
164
|
+
ActionMailer.deprecator.warn <<~MSG
|
165
|
+
Passing a Hash to the assert_enqueued_email_with :args kwarg causes the
|
166
|
+
Hash to be treated as params. This behavior is deprecated and will be
|
167
|
+
removed in Rails 7.2.
|
168
|
+
|
169
|
+
To specify a params Hash, use the :params kwarg:
|
170
|
+
|
171
|
+
assert_enqueued_email_with MyMailer, :my_method, params: { my_param: "value" }
|
172
|
+
|
173
|
+
Or, to specify named mailer args as a Hash, wrap the Hash in an array:
|
174
|
+
|
175
|
+
assert_enqueued_email_with MyMailer, :my_method, args: [{ my_arg: "value" }]
|
176
|
+
# OR
|
177
|
+
assert_enqueued_email_with MyMailer, :my_method, args: [my_arg: "value"]
|
178
|
+
MSG
|
179
|
+
|
180
|
+
params, args = args, nil
|
181
|
+
end
|
182
|
+
|
183
|
+
args = Array(args) unless args.is_a?(Proc)
|
184
|
+
queue ||= mailer.deliver_later_queue_name || ActiveJob::Base.default_queue_name
|
185
|
+
|
186
|
+
expected = ->(job_args) do
|
187
|
+
job_kwargs = job_args.extract_options!
|
188
|
+
|
189
|
+
[mailer.to_s, method.to_s, "deliver_now"] == job_args &&
|
190
|
+
params === job_kwargs[:params] && args === job_kwargs[:args]
|
191
|
+
end
|
192
|
+
|
193
|
+
assert_enqueued_with(job: mailer.delivery_job, args: expected, queue: queue.to_s, &block)
|
133
194
|
end
|
134
195
|
|
135
196
|
# Asserts that no emails are enqueued for later delivery.
|
@@ -151,6 +212,68 @@ module ActionMailer
|
|
151
212
|
assert_enqueued_emails 0, &block
|
152
213
|
end
|
153
214
|
|
215
|
+
# Delivers all enqueued emails. If a block is given, delivers all of the emails
|
216
|
+
# that were enqueued throughout the duration of the block. If a block is
|
217
|
+
# not given, delivers all the enqueued emails up to this point in the test.
|
218
|
+
#
|
219
|
+
# def test_deliver_enqueued_emails
|
220
|
+
# deliver_enqueued_emails do
|
221
|
+
# ContactMailer.welcome.deliver_later
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# assert_emails 1
|
225
|
+
# end
|
226
|
+
#
|
227
|
+
# def test_deliver_enqueued_emails_without_block
|
228
|
+
# ContactMailer.welcome.deliver_later
|
229
|
+
#
|
230
|
+
# deliver_enqueued_emails
|
231
|
+
#
|
232
|
+
# assert_emails 1
|
233
|
+
# end
|
234
|
+
#
|
235
|
+
# If the +:queue+ option is specified,
|
236
|
+
# then only the emails(s) enqueued to a specific queue will be performed.
|
237
|
+
#
|
238
|
+
# def test_deliver_enqueued_emails_with_queue
|
239
|
+
# deliver_enqueued_emails queue: :external_mailers do
|
240
|
+
# CustomerMailer.deliver_later_queue_name = :external_mailers
|
241
|
+
# CustomerMailer.welcome.deliver_later # will be performed
|
242
|
+
# EmployeeMailer.deliver_later_queue_name = :internal_mailers
|
243
|
+
# EmployeeMailer.welcome.deliver_later # will not be performed
|
244
|
+
# end
|
245
|
+
#
|
246
|
+
# assert_emails 1
|
247
|
+
# end
|
248
|
+
#
|
249
|
+
# If the +:at+ option is specified, then only delivers emails enqueued to deliver
|
250
|
+
# immediately or before the given time.
|
251
|
+
def deliver_enqueued_emails(queue: nil, at: nil, &block)
|
252
|
+
perform_enqueued_jobs(only: ->(job) { delivery_job_filter(job) }, queue: queue, at: at, &block)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Returns any emails that are sent in the block.
|
256
|
+
#
|
257
|
+
# def test_emails
|
258
|
+
# emails = capture_emails do
|
259
|
+
# ContactMailer.welcome.deliver_now
|
260
|
+
# end
|
261
|
+
# assert_equal "Hi there", emails.first.subject
|
262
|
+
#
|
263
|
+
# emails = capture_emails do
|
264
|
+
# ContactMailer.welcome.deliver_now
|
265
|
+
# ContactMailer.welcome.deliver_later
|
266
|
+
# end
|
267
|
+
# assert_equal "Hi there", emails.first.subject
|
268
|
+
# end
|
269
|
+
def capture_emails(&block)
|
270
|
+
original_count = ActionMailer::Base.deliveries.size
|
271
|
+
deliver_enqueued_emails(&block)
|
272
|
+
new_count = ActionMailer::Base.deliveries.size
|
273
|
+
diff = new_count - original_count
|
274
|
+
ActionMailer::Base.deliveries.last(diff)
|
275
|
+
end
|
276
|
+
|
154
277
|
private
|
155
278
|
def delivery_job_filter(job)
|
156
279
|
job_class = job.is_a?(Hash) ? job.fetch(:job) : job.class
|