Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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
Brian Cardarella bcardarella authored
41 actionmailer/lib/action_mailer/async.rb
View
@@ -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
7 actionmailer/lib/action_mailer/base.rb
View
@@ -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:
14 actionmailer/test/base_test.rb
View
@@ -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
1  actionmailer/test/fixtures/async_mailer/welcome.erb
View
@@ -0,0 +1 @@
+Welcome
3  actionmailer/test/mailers/async_mailer.rb
View
@@ -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.