Updating Devise Trackable Last User Sign-In Time with Devise Rememberable

Back | devise, rails, ruby | 2/8/2012 |

Devise has a :trackable strategy which updates the user’s last sign-in time, remote IP and increments a counter in the User model upon successful logon. This is implemented in Devise::Models::Trackable.update_tracked_fields! and invoked as a Warden callback in devise/hooks/trackable.rb.

  1. Warden::Manager.after_set_user :except => :fetch do |record, warden, options|
  2.   if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && !warden.request.env['devise.skip_trackable']
  3.     record.update_tracked_fields!(warden.request)
  4.   end
  5. end

Warden will invoke the callback every time warden.set_user is called, which is done once per logon with :event => :authenticate in the options. But when used with the :rememberable strategy, a returning user is not logging on – he continues a previous session. The callback is invoked with an :event => :fetch in the options, which is explicitly excluded in the code above.

Of course, we might not see things in the same eye. A user returning 24 hours later might as well be logging in again. Lets add a callback that will update tracked fields in this case (to config/initializers/devise_trackable.rb).

  1. Warden::Manager.after_set_user do |record, warden, options|
  2.   if record.respond_to?(:update_tracked_fields!) && warden.authenticated?(options[:scope]) && ! warden.request.env['devise.skip_trackable'] &&
  3.     (record.last_sign_in_at.nil? || (Date.today - record.last_sign_in_at.to_date).to_i >= 1)
  4.     record.update_tracked_fields!(warden.request)
  5.   end
  6. end

Is there a better way to do this? Maybe something worth contributing in one way or another to Devise?