Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Asynchronous ActionMailer

Any ActionMailer class can be set to render and delier messages using
the new Rails Queue.

Some of this work was borrowed (with permission) from Nick Plante's
(zapnap) reqsue_mailer gem.
  • Loading branch information...
commit dc7fd821dca0b2088bde7e0a2a06bfe59e1ba5c6 1 parent 3726080
@bcardarella bcardarella authored
View
41 actionmailer/lib/action_mailer/async.rb
@@ -0,0 +1,41 @@
+module ActionMailer::Async
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ def method_missing(method_name, *args)
+ if action_methods.include?(method_name.to_s)
+ QueuedMessage.new(self, method_name, *args)
+ else
+ super
+ end
+ end
+ end
+
+ class QueuedMessage
+ delegate :to_s, :to => :actual_message
+
+ def initialize(mailer_class, method_name, *args)
+ @mailer_class = mailer_class
+ @method_name = method_name
+ *@args = *args
+ end
+
+ def run
+ actual_message.deliver
+ end
+
+ def deliver
+ Rails.queue << self
+ end
+
+ def actual_message
+ @actual_message ||= @mailer_class.send(:new, @method_name, *@args).message
+ end
+
+ def method_missing(method_name, *args)
+ actual_message.send(method_name, *args)
+ end
+ end
+end
View
7 actionmailer/lib/action_mailer/base.rb
@@ -456,6 +456,13 @@ def respond_to?(method, include_private = false) #:nodoc:
super || action_methods.include?(method.to_s)
end
+ def async=(truth)
+ if truth
+ require 'action_mailer/async'
+ include ActionMailer::Async
+ end
+ end
+
protected
def set_payload_for_mail(payload, mail) #:nodoc:
View
14 actionmailer/test/base_test.rb
@@ -7,6 +7,9 @@
require 'mailers/base_mailer'
require 'mailers/proc_mailer'
require 'mailers/asset_mailer'
+require 'mailers/async_mailer'
+
+require 'rails/queueing'
class BaseTest < ActiveSupport::TestCase
def teardown
@@ -419,6 +422,16 @@ def teardown
assert_equal(1, BaseMailer.deliveries.length)
end
+ test "delivering message asynchronously" do
+ Rails.stubs(:queue).returns(Rails::Queueing::TestQueue.new)
+ AsyncMailer.delivery_method = :test
+ AsyncMailer.deliveries.clear
+ AsyncMailer.welcome.deliver
+ assert_equal(0, AsyncMailer.deliveries.length)
+ Rails.queue.drain
+ assert_equal(1, AsyncMailer.deliveries.length)
+ end
+
test "calling deliver, ActionMailer should yield back to mail to let it call :do_delivery on itself" do
mail = Mail::Message.new
mail.expects(:do_delivery).once
@@ -434,6 +447,7 @@ def teardown
end
test "should raise if missing template in implicit render" do
+ BaseMailer.deliveries.clear
assert_raises ActionView::MissingTemplate do
BaseMailer.implicit_different_template('missing_template').deliver
end
View
1  actionmailer/test/fixtures/async_mailer/welcome.erb
@@ -0,0 +1 @@
+Welcome
View
3  actionmailer/test/mailers/async_mailer.rb
@@ -0,0 +1,3 @@
+class AsyncMailer < BaseMailer
+ self.async = true
+end
Please sign in to comment.
Something went wrong with that request. Please try again.