You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When changing an user's email address with reconfirmable set to true, two calls to send_devise_notification are made, one for :email_changed and one for :confirmation_instructions.
The first of those two is called within an after_update hook, meaning it is called after save has been called, but before being properly committed to the database.
When the notification is handled in a worker, the worker may load the model before the changes have been committed to the database, thus operating on old data.
# # Deliver later with Active Job's `deliver_later`
# if message.respond_to?(:deliver_later)
# message.deliver_later
# # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
# elsif message.respond_to?(:deliver_now)
# message.deliver_now
# else
# message.deliver
# end
# end
#
# end
hint at a way to do that, but neither changed? nor saved_changes? actually differentiate between the after_update and the after_commit situation. Using one variant will make both mailers execute immediately, not solving the problem, and using the other variant will make both notifications be enqueued, but process the queue before the second notification gets queued.
Expected behavior
send_devise_notification should only be called in after_commit hooks, or, alternatively, the documentation should describe a way to properly handle the case where some notifications are sent from after_update hooks and others from after_commit hooks.
The text was updated successfully, but these errors were encountered:
In Mastodon, we ended up checking whether we are in a transaction, if so queue the notifications, otherwise send them right away. The relevant pieces of code look like this:
classUser < ApplicationRecordafter_commit:send_pending_devise_notificationsdefsend_devise_notification(notification, *args, **kwargs)# This method can be called in `after_update` and `after_commit` hooks,# but we must make sure the mailer is actually called *after* commit,# otherwise it may work on stale data. To do this, figure out if we are# within a transaction.# It seems like devise sends keyword arguments as a hash in the last# positional argumentkwargs=args.popifargs.last.is_a?(Hash) && kwargs.empty?ifActiveRecord::Base.connection.current_transaction.try(:records)&.include?(self)pending_devise_notifications << [notification,args,kwargs]elserender_and_send_devise_message(notification, *args, **kwargs)endenddefsend_pending_devise_notificationspending_devise_notifications.eachdo |notification,args,kwargs|
render_and_send_devise_message(notification, *args, **kwargs)end# Empty the pending notifications array because the# after_commit hook can be called multiple times which# could cause multiple emails to be sent.pending_devise_notifications.clearenddefpending_devise_notifications@pending_devise_notifications ||= []endend
Environment
Current behavior
When changing an user's email address with
reconfirmable
set to true, two calls tosend_devise_notification
are made, one for:email_changed
and one for:confirmation_instructions
.The first of those two is called within an
after_update
hook, meaning it is called aftersave
has been called, but before being properly committed to the database.When the notification is handled in a worker, the worker may load the model before the changes have been committed to the database, thus operating on old data.
The comments in
devise/lib/devise/models/authenticatable.rb
Lines 133 to 194 in 406915c
changed?
norsaved_changes?
actually differentiate between theafter_update
and theafter_commit
situation. Using one variant will make both mailers execute immediately, not solving the problem, and using the other variant will make both notifications be enqueued, but process the queue before the second notification gets queued.Expected behavior
send_devise_notification
should only be called inafter_commit
hooks, or, alternatively, the documentation should describe a way to properly handle the case where some notifications are sent fromafter_update
hooks and others fromafter_commit
hooks.The text was updated successfully, but these errors were encountered: