Skip to content

Commit

Permalink
Provide a send_devise_notification hook
Browse files Browse the repository at this point in the history
  • Loading branch information
José Valim committed Jun 16, 2012
1 parent 85c9067 commit 18a18e4
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 4 deletions.
37 changes: 37 additions & 0 deletions lib/devise/models/authenticatable.rb
Expand Up @@ -134,6 +134,43 @@ def #{method}(options=nil)
RUBY
end

protected

# 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

This comment has been minimized.

Copy link
@pixeltrix

pixeltrix Mar 1, 2013

Contributor

As a PSA to anyone else, you'll want to clear the pending notifications array after sending them because after_commit can be called multiple times. If you don't you'll end up spamming your new user with multiple copies of the email message. Also after_commit won't be called if your record isn't a new record or hasn't been changed - in this case your send_devise_notification method will be something like this:

  def send_devise_notification(notification)
    if new_record? || changed?
      pending_notifications << notification
    else
      devise_mailer.send(notification, self).deliver
    end
  end

You'll want to check for new_record? and changed? because User.new.changed? => false.

This comment has been minimized.

Copy link
@lucasmazza

lucasmazza Mar 1, 2013

Contributor

@pixeltrix nice catch, I think it's better to update the related documentation. Feel free to send a PR ❤️

This comment has been minimized.

Copy link
@pixeltrix

pixeltrix Mar 1, 2013

Contributor

@lucasmazza will do 😄

#
# def pending_notifications
# @pending_notifications ||= []
# end
# end
#
def send_devise_notification(notification)
devise_mailer.send(notification, self).deliver
end

module ClassMethods
Devise::Models.config(self, :authentication_keys, :request_keys, :strip_whitespace_keys,
:case_insensitive_keys, :http_authenticatable, :params_authenticatable, :skip_session_storage)
Expand Down
4 changes: 2 additions & 2 deletions lib/devise/models/confirmable.rb
Expand Up @@ -78,7 +78,7 @@ def send_confirmation_instructions
@reconfirmation_required = false

generate_confirmation_token! if self.confirmation_token.blank?
self.devise_mailer.confirmation_instructions(self).deliver
send_devise_notification(:confirmation_instructions)
end

# Resend confirmation token. This method does not need to generate a new token.
Expand Down Expand Up @@ -125,7 +125,7 @@ def headers_for(action)
# instructions on creation. This can be overriden
# in models to map to a nice sign up e-mail.
def send_on_create_confirmation_instructions
self.devise_mailer.confirmation_instructions(self).deliver
send_devise_notification(:confirmation_instructions)
end

# Callback to overwrite if confirmation is required or not.
Expand Down
2 changes: 1 addition & 1 deletion lib/devise/models/lockable.rb
Expand Up @@ -60,7 +60,7 @@ def access_locked?

# Send unlock instructions by email
def send_unlock_instructions
self.devise_mailer.unlock_instructions(self).deliver
send_devise_notification(:unlock_instructions)
end

# Resend the unlock instructions if the user is locked.
Expand Down
2 changes: 1 addition & 1 deletion lib/devise/models/recoverable.rb
Expand Up @@ -45,7 +45,7 @@ def reset_password!(new_password, new_password_confirmation)
# Resets reset password token and send reset password instructions by email
def send_reset_password_instructions
generate_reset_password_token! if should_generate_reset_token?
self.devise_mailer.reset_password_instructions(self).deliver
send_devise_notification(:reset_password_instructions)
end

# Checks if the reset password token sent is within the limit time.
Expand Down

0 comments on commit 18a18e4

Please sign in to comment.