7

I'm trying to override the method 'send_confirmation_instructions' as shown here:

http://trackingrails.com/posts/devise-send-confirmation-mail-manually-or-delay-them

with:

def send_confirmation_instructions
    generate_confirmation_token! if self.confirmation_token.nil?
    ::Devise.mailer.delay.confirmation_instructions(self)
end

This seems to no longer work with the latest version of devise. The devise docs show how to override a controller but not a model. Any suggestions on how to override a devise model? Thanks

AnApprentice
  • 108,152
  • 195
  • 629
  • 1,012

2 Answers2

9

When you set up Devise, you tell it which model it's working on (e.g. User); many/most of its methods then apply to that class. So that's where you'll want to override stuff.

Here's a comment from the Devise code at lib/devise/models/authenticatable.rb that describes almost exactly what you want to do, if I am reading correctly.

  # This is an internal method called every time Devise needs
  # to send a notification/mail. This can be overriden if you
  # need to customize the e-mail delivery logic. For instance,
  # if you are using a queue to deliver e-mails (delayed job,
  # sidekiq, resque, etc), you must add the delivery to the queue
  # just after the transaction was committed. To achieve this,
  # you can override send_devise_notification to store the
  # deliveries until the after_commit callback is triggered:
  #
  #     class User
  #       devise :database_authenticatable, :confirmable
  #
  #       after_commit :send_pending_notifications
  #
  #       protected
  #
  #       def send_devise_notification(notification)
  #         pending_notifications << notification
  #       end
  #
  #       def send_pending_notifications
  #         pending_notifications.each do |n|
  #           devise_mailer.send(n, self).deliver
  #         end
  #       end
  #
  #       def pending_notifications
  #         @pending_notifications ||= []
  #       end
  #     end
  #
  def send_devise_notification(notification)
    devise_mailer.send(notification, self).deliver
  end
Tom Harrison
  • 13,533
  • 3
  • 49
  • 77
  • Thanks so you're saying add "send_devise_notification" to my user.rb file? I tried that and it did not get called... – AnApprentice Oct 11 '12 at 03:17
  • Yes, override `send_devise_notification` in your User model. I was able to intercept the notification (I just sent somethig to the log to prove it works) with a current version of Devise. But to get everything working, read the comment -- it's not just a matter of defining the method, you also have to add the `after_commit` filter to build up the delayed job (or whatever) queue. – Tom Harrison Oct 11 '12 at 03:36
  • Thanks but this isn't where "send_confirmation_instructions" lives? and I need to modify that method "send_confirmation_instructions" – AnApprentice Oct 11 '12 at 03:53
  • 1
    True, this would override all Devise-managed notifications. By adding `devise :confirmable` (and other `able` options) to your User model, you are in effect including their methods in User. So to override the specific method `send_confirmation_instructions` (which is defined in `lib/devise/models/confirmable.rb`) you would declare it in your user model. You still may need to override `send_devise_notification` if what you want is the delayed sending. I don't see anything built in to Devise (current version) that specifically manages delayed sending, so perhaps this is what isn't clicking. – Tom Harrison Oct 11 '12 at 04:04
  • 1
    Thanks but that's what I tried I added a "send_confirmation_instructions" method to user.rb and it is never called – AnApprentice Oct 11 '12 at 04:19
  • Sorry dude, I got nothin' more. Read the Devise code, it's far better commented than it is documented externally on GitHub. I am confident that what I am suggesting is correct, since something similar is working in my code now. – Tom Harrison Oct 11 '12 at 04:23
  • More updated docs can be found here: https://github.com/plataformatec/devise/blob/master/lib/devise/models/authenticatable.rb – lordB8r Dec 02 '14 at 15:54
0

Why not use devise-async?

Usage

Devise >= 2.1.1

Include Devise::Async::Model to your Devise model

class User < ActiveRecord::Base
  devise :database_authenticatable, :confirmable # etc ...

  include Devise::Async::Model # should be below call to `devise`
end

Devise < 2.1.1

Set Devise::Async::Proxy as Devise's mailer in config/initializers/devise.rb:

# Configure the class responsible to send e-mails.
config.mailer = "Devise::Async::Proxy"

All

Set your queuing backend by creating config/initializers/devise_async.rb:

# Supported options: :resque, :sidekiq, :delayed_job
Devise::Async.backend = :resque
Nick Colgan
  • 5,488
  • 25
  • 36
  • Because devise-async does not store the virtual attributes you set on a user (attr_accessor). – AnApprentice Oct 11 '12 at 03:17
  • If you want to use latest version of devise this is no longer an option, as you can see in [their docs](https://github.com/mhfs/devise-async#devise--40) they do not support Devise >= 4.0 – David Revelo May 05 '17 at 16:33