diff options
author | Jeremy Daer <jeremydaer@gmail.com> | 2016-05-13 17:43:48 -0700 |
---|---|---|
committer | Jeremy Daer <jeremydaer@gmail.com> | 2016-05-15 18:44:16 -0700 |
commit | e35b98e6f5c54330245645f2ed40d56c74538902 (patch) | |
tree | 272bba30020bde27d177d2cf6227dfa8bb7a525f /actionmailer/test | |
parent | 6810847f495cd282c2659be738ac8271ecdec12f (diff) | |
download | rails-e35b98e6f5c54330245645f2ed40d56c74538902.tar.gz rails-e35b98e6f5c54330245645f2ed40d56c74538902.tar.bz2 rails-e35b98e6f5c54330245645f2ed40d56c74538902.zip |
Action Mailer: Declarative exception handling with `rescue_from`.
Follows the same pattern as controllers and jobs. Exceptions raised in
delivery jobs (enqueued by `#deliver_later`) are also delegated to the
mailer's rescue_from handlers, so you can handle the DeserializationError
raised by delivery jobs:
```ruby
class MyMailer < ApplicationMailer
rescue_from ActiveJob::DeserializationError do
…
end
```
ActiveSupport::Rescuable polish:
* Add the `rescue_with_handler` class method so exceptions may be
handled at the class level without requiring an instance.
* Rationalize `exception.cause` handling. If no handler matches the
exception, fall back to the handler that matches its cause.
* Handle exceptions raised elsewhere. Pass `object: …` to execute
the `rescue_from` handler (e.g. a method call or a block to
instance_exec) against a different object. Defaults to `self`.
Diffstat (limited to 'actionmailer/test')
-rw-r--r-- | actionmailer/test/mailers/delayed_mailer.rb | 20 | ||||
-rw-r--r-- | actionmailer/test/message_delivery_test.rb | 51 |
2 files changed, 70 insertions, 1 deletions
diff --git a/actionmailer/test/mailers/delayed_mailer.rb b/actionmailer/test/mailers/delayed_mailer.rb index 62d4baa434..e6211ef028 100644 --- a/actionmailer/test/mailers/delayed_mailer.rb +++ b/actionmailer/test/mailers/delayed_mailer.rb @@ -1,6 +1,26 @@ +require 'active_job/arguments' + +class DelayedMailerError < StandardError; end + class DelayedMailer < ActionMailer::Base + cattr_accessor :last_error + cattr_accessor :last_rescue_from_instance + + rescue_from DelayedMailerError do |error| + @@last_error = error + @@last_rescue_from_instance = self + end + + rescue_from ActiveJob::DeserializationError do |error| + @@last_error = error + @@last_rescue_from_instance = self + end def test_message(*) mail(from: 'test-sender@test.com', to: 'test-receiver@test.com', subject: 'Test Subject', body: 'Test Body') end + + def test_raise(klass_name) + raise klass_name.constantize, 'boom' + end end diff --git a/actionmailer/test/message_delivery_test.rb b/actionmailer/test/message_delivery_test.rb index f06d69369f..aaed94d519 100644 --- a/actionmailer/test/message_delivery_test.rb +++ b/actionmailer/test/message_delivery_test.rb @@ -12,16 +12,23 @@ class MessageDeliveryTest < ActiveSupport::TestCase ActionMailer::Base.deliver_later_queue_name = :test_queue ActionMailer::Base.delivery_method = :test ActiveJob::Base.logger = Logger.new(nil) - @mail = DelayedMailer.test_message(1, 2, 3) ActionMailer::Base.deliveries.clear ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true + + DelayedMailer.last_error = nil + DelayedMailer.last_rescue_from_instance = nil + + @mail = DelayedMailer.test_message(1, 2, 3) end teardown do 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 end test 'should have a message' do @@ -101,4 +108,46 @@ class MessageDeliveryTest < ActiveSupport::TestCase @mail.deliver_later end end + + test 'job delegates error handling to mailer' do + # Superclass not rescued by mailer's rescue_from RuntimeError + message = DelayedMailer.test_raise('StandardError') + assert_raise(StandardError) { message.deliver_later } + assert_nil DelayedMailer.last_error + assert_nil DelayedMailer.last_rescue_from_instance + + # Rescued by mailer's rescue_from RuntimeError + message = DelayedMailer.test_raise('DelayedMailerError') + assert_nothing_raised { message.deliver_later } + assert_equal 'boom', DelayedMailer.last_error.message + assert_kind_of DelayedMailer, DelayedMailer.last_rescue_from_instance + end + + class DeserializationErrorFixture + include GlobalID::Identification + + def self.find(id) + raise 'boom, missing find' + end + + attr_reader :id + def initialize(id = 1) + @id = id + end + + def to_global_id(options = {}) + super app: 'foo' + end + end + + test 'job delegates deserialization errors to mailer class' do + # Inject an argument that can't be deserialized. + message = DelayedMailer.test_message(DeserializationErrorFixture.new) + + # DeserializationError is raised, rescued, and delegated to the handler + # on the mailer class. + assert_nothing_raised { message.deliver_later } + assert_equal DelayedMailer, DelayedMailer.last_rescue_from_instance + assert_equal 'Error while trying to deserialize arguments: boom, missing find', DelayedMailer.last_error.message + end end |