Reputation: 851
I want to add a feature that will redirect a user with an expired password to the reset password page. My controller looks like this
class Users::SessionsController < Devise::SessionsController
def create
user = User.find_by(email: params[:user][:email].downcase)
if user.password_expire?
raw, enc = Devise.token_generator.generate(current_user.class,
:reset_password_token)
user.reset_password_token = enc
user.reset_password_sent_at = Time.now.utc
user.save(validate: false)
redirect_to edit_password_url(user, reset_password_token: raw)
else
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in)
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
end
end
When I debug with binding.pry at the top of the action, I find that current_user exists and user_signed_in? is true. How is it possible I'm signed in before the create method completes?
Upvotes: 1
Views: 1671
Reputation: 441
If you are using the security extension you don't need at all to take care of the implementation of password expiration. And if you are not using it, you should check it out - devise_security_extension.
Upvotes: 2
Reputation: 6278
Devise remembers the current user using cookies until they log out.
Just because they've hit your sign in route doesn't mean they're signed out.
Tracing the code in Devise to understand what happens we see:
1. Devise::SessionsController#create
class Devise::SessionsController < ApplicationController
# ...
def create
# ...
sign_in(resource_name, resource)
# ...
end
end
2. Devise::Controllers::Helpers#sign_in
def sign_in(resource_or_scope, *args)
# ...
if options[:bypass]
warden.session_serializer.store(resource, scope)
elsif warden.user(scope) == resource && !options.delete(:force)
# Do nothing. User already signed in and we are not forcing it.
true # <=== Here's the moment of truth
else
# ...
end
sessions#create
when they're already logged inUpvotes: 1