aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer
diff options
context:
space:
mode:
Diffstat (limited to 'actionmailer')
-rw-r--r--actionmailer/CHANGELOG.md13
-rw-r--r--actionmailer/lib/action_mailer/base.rb24
-rw-r--r--actionmailer/lib/action_mailer/log_subscriber.rb24
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb2
-rw-r--r--actionmailer/test/abstract_unit.rb7
-rw-r--r--actionmailer/test/base_test.rb39
6 files changed, 95 insertions, 14 deletions
diff --git a/actionmailer/CHANGELOG.md b/actionmailer/CHANGELOG.md
index 4e3a9daf7d..ab93745f60 100644
--- a/actionmailer/CHANGELOG.md
+++ b/actionmailer/CHANGELOG.md
@@ -1,3 +1,16 @@
+* 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.
+
+ *Richard Schneeman*
+
+* Raise an exception when attachments are added after `mail` was called.
+ This is a safeguard to prevent invalid emails.
+
+ Fixes #16163.
+
+ *Yves Senn*
+
* Add `config.action_mailer.show_previews` configuration option.
This config option can be used to enable the mail preview in environments
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 135cf35ac0..bc540aece0 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -394,7 +394,7 @@ module ActionMailer
# implement for a custom delivery agent.
#
# * <tt>perform_deliveries</tt> - Determines whether emails are actually sent from Action Mailer when you
- # call <tt>.deliver</tt> on an mail message or on an Action Mailer method. This is on by default but can
+ # call <tt>.deliver</tt> on an email message or on an Action Mailer method. This is on by default but can
# be turned off to aid in functional testing.
#
# * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with
@@ -649,7 +649,22 @@ module ActionMailer
# mail.attachments[0] # => Mail::Part (first attachment)
#
def attachments
- @_message.attachments
+ if @_mail_was_called
+ LateAttachmentsProxy.new(@_message.attachments)
+ else
+ @_message.attachments
+ end
+ end
+
+ class LateAttachmentsProxy < SimpleDelegator
+ def inline; _raise_error end
+ def []=(_name, _content); _raise_error end
+
+ private
+ def _raise_error
+ raise RuntimeError, "Can't add attachments after `mail` was called.\n" \
+ "Make sure to use `attachments[]=` before calling `mail`."
+ end
end
# The main method that creates the message and renders the email templates. There are
@@ -882,6 +897,11 @@ module ActionMailer
container.add_part(part)
end
+ # Emails do not support relative path links.
+ def self.supports_path?
+ false
+ end
+
ActiveSupport.run_load_hooks(:action_mailer, self)
end
end
diff --git a/actionmailer/lib/action_mailer/log_subscriber.rb b/actionmailer/lib/action_mailer/log_subscriber.rb
index e4aaab34b1..5b57c75ec3 100644
--- a/actionmailer/lib/action_mailer/log_subscriber.rb
+++ b/actionmailer/lib/action_mailer/log_subscriber.rb
@@ -6,25 +6,27 @@ module ActionMailer
class LogSubscriber < ActiveSupport::LogSubscriber
# An email was delivered.
def deliver(event)
- return unless logger.info?
- recipients = Array(event.payload[:to]).join(', ')
- info("\nSent mail to #{recipients} (#{event.duration.round(1)}ms)")
- debug(event.payload[:mail])
+ info do
+ recipients = Array(event.payload[:to]).join(', ')
+ "\nSent mail to #{recipients} (#{event.duration.round(1)}ms)"
+ end
+
+ debug { event.payload[:mail] }
end
# An email was received.
def receive(event)
- return unless logger.info?
- info("\nReceived mail (#{event.duration.round(1)}ms)")
- debug(event.payload[:mail])
+ info { "\nReceived mail (#{event.duration.round(1)}ms)" }
+ debug { event.payload[:mail] }
end
# An email was generated.
def process(event)
- return unless logger.debug?
- mailer = event.payload[:mailer]
- action = event.payload[:action]
- debug("\n#{mailer}##{action}: processed outbound mail in #{event.duration.round(1)}ms")
+ debug do
+ mailer = event.payload[:mailer]
+ action = event.payload[:action]
+ "\n#{mailer}##{action}: processed outbound mail in #{event.duration.round(1)}ms"
+ end
end
# Use the logger configured for ActionMailer::Base
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 6f760732e2..c62d4b5082 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -30,7 +30,7 @@ module ActionMailer
ActiveSupport.on_load(:action_mailer) do
include AbstractController::UrlFor
- extend ::AbstractController::Railties::RoutesHelpers.with(app.routes)
+ extend ::AbstractController::Railties::RoutesHelpers.with(app.routes, false)
include app.routes.mounted_helpers
register_interceptors(options.delete(:interceptors))
diff --git a/actionmailer/test/abstract_unit.rb b/actionmailer/test/abstract_unit.rb
index 2e5242f0b1..28727b62ec 100644
--- a/actionmailer/test/abstract_unit.rb
+++ b/actionmailer/test/abstract_unit.rb
@@ -49,3 +49,10 @@ end
def jruby_skip(message = '')
skip message if defined?(JRUBY_VERSION)
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/base_test.rb b/actionmailer/test/base_test.rb
index 229ded8e04..6116d1e29f 100644
--- a/actionmailer/test/base_test.rb
+++ b/actionmailer/test/base_test.rb
@@ -232,6 +232,45 @@ class BaseTest < ActiveSupport::TestCase
end
end
+ test "adding attachments after mail was called raises exception" do
+ class LateAttachmentMailer < ActionMailer::Base
+ def welcome
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+ attachments['invoice.pdf'] = 'This is test File content'
+ end
+ end
+
+ e = assert_raises(RuntimeError) { LateAttachmentMailer.welcome }
+ assert_match(/Can't add attachments after `mail` was called./, e.message)
+ end
+
+ test "adding inline attachments after mail was called raises exception" do
+ class LateInlineAttachmentMailer < ActionMailer::Base
+ def welcome
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+ attachments.inline['invoice.pdf'] = 'This is test File content'
+ end
+ end
+
+ e = assert_raises(RuntimeError) { LateInlineAttachmentMailer.welcome }
+ assert_match(/Can't add attachments after `mail` was called./, e.message)
+ end
+
+ test "accessing attachments works after mail was called" do
+ class LateAttachmentAccessorMailer < ActionMailer::Base
+ def welcome
+ attachments['invoice.pdf'] = 'This is test File content'
+ mail body: "yay", from: "welcome@example.com", to: "to@example.com"
+
+ unless attachments.map(&:filename) == ["invoice.pdf"]
+ raise Minitest::Assertion, "Should allow access to attachments"
+ end
+ end
+ end
+
+ assert_nothing_raised { LateAttachmentAccessorMailer.welcome }
+ end
+
# Implicit multipart
test "implicit multipart" do
email = BaseMailer.implicit_multipart