I have a basic authentication system just like in Michael Hartl’s Ruby on Rails Tutorial. Basically, a remember token is stored in a cookie. I implemented Ryan Bate’s Beta-Invitations from Railscast #124, where you can send a limited number of invitations. While doing that, I ran into the problem that the current user got logged out after sending an invitation. This was caused by this code in the invitation model:
invitation.rb
belongs_to :sender, :class_name => 'User'
[...]
before_create :decrement_sender_count, :if => :sender
[...]
def decrement_sender_count
sender.decrement! :invitation_limit
end
In the logs I saw that sender.decrement! not only updated the invitation_limit but the remember_token as well:
UPDATE "users" SET "invitation_limit" = 9982, "remember_token" = 'PYEWo_om0iaMjwltU4iRBg', "updated_at" = '2012-07-06 09:57:43.354922' WHERE "users"."id" = 1
I found an ugly workaround but I would love to know what the problem really is. Since I don’t know where to start, I’ll show you the update method from the users controller. What else could be relevant?
users_controller.rb
def update
@user = User.find(params[:id])
if @user.update_attributes(params[:user])
flash[:success] = t('success.profile_save')
sign_in @user
redirect_to @user
else
flash.now[:error] = t('error.profile_save')
render 'edit'
end
end
decrement!callssavewhich of course fires save callbacks. It looks like the book directs you to dowhich means that saving a user will always invalidate the remember token. I assume this is so that when a user changes their password the remember token changes too, but it means that there is obviously some collateral damage.
You could use the
decrement_counterwhich in essence doeswithout running any callbacks. This also avoids some race condition scenarios. However changing the token whenever the user changes is bound to change the token at times when you don’t expect it – you might want to only change it when relevant (perhaps when credentials have changed)