I have being using Devise, and relying on last_sign_in_at of the user model to work out if my customers have not returned within X days. However, I recently discovered that last_sign_in_at is only updated when an actual form log in event occurs, as opposed to when a user is logged in automatically due to the inclusion of rememberable.
If want to ensure that last_sign_in_at is updated each time a user logs in (a new browser session), regardless of whether they used a form to log in or were automatically logged in by the rememberable cookie, how would I go about doing this in a Devise-compatible way?
On the application_controller
you can set a before_action
that checks if the current_sign_in_at of the current user is longer then X ago. If it is, then use sign_in(current_user, force: true)
that updates the current_sign_in_at.
before_action :update_last_sign_in_at
def update_last_sign_in_at
return unless user_signed_in? && current_user.current_sign_in_at < 12.hours.ago
sign_in(current_user, force: true)
end
I use it so to detect inactive users (not signed in for 6 months) and delete them. #GDPR
Taking Matthew's solution, I think the code should be the following (note the not-operator before the session[:logged_signin]):
before_filter :update_last_sign_in_at
protected
def update_last_sign_in_at
if user_signed_in? && !session[:logged_signin]
sign_in(current_user, :force => true)
session[:logged_signin] = true
end
end
The trackable hook is from Warden's after_set_user hook -- what you could do to easily remedy this is set a before_filter to call sign_in.
This could be optimized, but test to see if using
before_filter proc{ sign_in(current_user, :force => true) }
updates the last_signed_in_at timestamp.
Devise: rememberable means that last_sign_in_at is not updated by trackable
Expanding on previous solutions, the problem with them would be that if the user signs in normally, they will "sign in twice". Which will set last_sign_in_at
to the same (or almost the same) value as current_sign_in_at
.
On my site, I use last_sign_in_at
to let the user know what has happened since last time they visited the site, and as such I need it to be somewhat accurate. Also, it logs +1 login count.
Also, there are people (like myself) who leave a browser window open for days without closing it (and hence never clearing the session flag). For metric purposes etc, it can be useful if such user behavior sometimes refresh the current_sign_in_at
time.
The below variants will remedy these things.
class ApplicationController < ActionController::Base
before_filter :update_sign_in_at_periodically
UPDATE_LOGIN_PERIOD = 10.hours
protected
def update_sign_in_at_periodically
if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago
session[:last_login_update_at] = Time.now
sign_in(current_user, :force => true) if user_signed_in?
end
end
end
However, when I try the above, using Devise 3.2.4, I do get a new login when it auto-logins by cookie (login-count +1 and current_sign_in_at
being set). So, I'm left with only the issue of wanting the tracking to periodically update even for users which keep the session open.
class ApplicationController < ActionController::Base
before_filter :update_sign_in_at_periodically
UPDATE_LOGIN_PERIOD = 10.hours
protected
def update_sign_in_at_periodically
# use session cookie to avoid hammering the database
if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago
session[:last_login_update_at] = Time.now
if user_signed_in? and current_user.current_sign_in_at < 1.minute.ago # prevents double logins
sign_in(current_user, :force => true)
end
end
end
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With