03:47 PMDevelopment, RubyStefano
Hello everyone.
I’d show a workaround to send email asynchronously using Devise and Rails3.
Suppose we have already up and running our application with Devise and delayed_job correctly installed.
A first attempt was to add in config/initializers the following file (devise_async.rb):
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#devise_async.rb
module Devise module Models module Confirmable handle_asynchronously :send_confirmation_instructions end module Recoverable handle_asynchronously :send_reset_password_instructions end module Lockable handle_asynchronously :send_unlock_instructions end end end |
This workaround has worked in part: the send method has been properly enqueued in the database, but when delayed_job tries to fire the job, the following error is raised:
1
2 |
User#send_confirmation_instructions_without_delay failed with NoMethodError: undefined method
'send_confirmation_instructions_without_delay'
for
# - 1 failed attempts
[Worker (host:stefano-desktop pid: 13153 ) ] |
As you can see, the job is trying to call the wrong send method: send_confirmation_instructions_without_delay.
At this point, I’ve implemented an even more dirty hack, overriding Devise’s methods using the syntax specified by intridea to send emails in the background:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
#devise_async.rb
module Devise module Models module Confirmable # Send confirmation instructions by email def send_confirmation_instructions generate_confirmation_token! if self. confirmation_token. nil? ::Devise. mailer. delay. confirmation_instructions ( self ) end end module Recoverable # Resets reset password token and send reset password instructions by email def send_reset_password_instructions generate_reset_password_token! ::Devise. mailer. delay. reset_password_instructions ( self ) end end module Lockable # Send unlock instructions by email def send_unlock_instructions ::Devise. mailer. delay. unlock_instructions ( self ) end end end end |
This solution, however, is too tied to the implementation of Devise and is therefore not a good one (besides being really really dirty).
The latest idea, which represents the solution I’ve used is implemented as follows: use the alias_method in this way:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
#devise_async.rb
module Devise module Models module Confirmable alias_method :send_confirmation_instructions_without_delay, :send_confirmation_instructions handle_asynchronously :send_confirmation_instructions end module Recoverable alias_method :send_reset_password_instructions_without_delay, :send_reset_password_instructions handle_asynchronously :send_reset_password_instructions end module Lockable alias_method :send_unlock_instructions_without_delay, :send_unlock_instructions handle_asynchronously :send_unlock_instructions end end end |
This latest hack works a treat; is not the best but let you send mail with Devise asynchronously.
If you have any better solutions, do not hesitate to share.