How to send mail asynchronously with Sorcery and Delayed Job in Rails 3
I’m developing a Rails 3.2 app and being fed up with devise, I decided I’d be switching to the awesome sorcery gem for user authentication. Sorcery has a ton of features while staying minimal (you still have to write all your models, controllers and views) and that is just what I need. Those devise controllers where driving me mad.
Anyways, after implementing it and testing the app, I noticed that every transaction was taking forever (5000-1000ms). That is because of the email delivery which is enclosed in a transaction (I have emails for activation, confirmation, reseting password and inviting other users).
The solution is obviously to handle asynchronously the email sending with a queue and workers. I decided to go with Delayed Job to keep everything on Active Record (Redis and the Resque gem rock quite a lot too).
To use Delayed Job you usually have to call:
Object.delay.method(args)
You can also call
handle_asynchronously :method_name
at the end of your controllers.
This is all very cool, but with Rails 3 mailers DJ breaks and usually can’t pick up parameters when using the handle_asynchronously method. Bummer.
With Sorcery, the code to send the emails is actually in the gem so the only solution is to override the gem’s methods to send the emails.
There are two ways to do that:
- Override the generic_send_mail method
- Override the single email sending methods
I went for option number 2 for the activation emails. In my user model:
def send_activation_needed_email!
UserMailer.delay.activation_needed_email(self.id)
end
def send_activation_success_email!
UserMailer.delay.activation_success_email(self.id)
end
This works fine but is not a viable approach for the password reset email, since its method initializes a bunch of stuff you shouldn’t mess with.
Then I realized that I overlooked the most clever way, and the simplest one.:
Edit your config/initializers/sorcery.rb file with the following:
config.user_config do |user|
user.user_activation_mailer = YourMailerName.delay
user.reset_password_mailer = YourMailerName.delay
end
In this way we make sure that every email is sent to the delay method via DJ, and we don’t have to worry about overriding Sorcery methods.
The simplest solution is always right under our eyes, yet still difficult to see.
Hope this helps.


