Tracking Devise User Logins & Sign-ups

I need to track the user activity being handled by the Devise gem. A set-up that’s lean, specific to Devise and easily limited to only logins for production. The following is what I came up with. The impressionist gem would have been an option but it’s a little much for my needs.

I’m working with Rails 4.0.2 / Ruby 2.0.0 / Devise 3.2.2. The full source code can be found in jehughes/rails4-example.


The first question is where to put the hooks into Devise?

(In other words, is this possible without creating a mess?)

I decided to use the ‘after’ action methods that are provided by Devise. The methods you override to redirect the user after they login, logout, etc.

For example, in app/controllers/local_devise/registrations_controller.rb :

We’ll define DeviseUsageLog and DeviseAction later.

Here’s a list where the logging was added in the same way as the method above:

applications_controller.rb after_sign_in_path_for
local_devise/unlocks_controller.rb after_unlock_path_for
local_devise/passwords_controller.rb after_resetting_password_path_for
local_devise/confirmations_controller.rb after_confirmation_path_for, after_confirmation_set_password_path_for
local_devise/registrations_controller.rb after_inactive_sign_up_path_for, after_sign_up_path_for, after_update_path_for

In addition, to log the deletion of a user account you’ll need to override the destroy method in local_devise/registrations_controller.rb :

I’m not tracking user logouts but that would be after_sign_out_path_for in applications_controller.rb. (Probably. Haven’t tried it out.)


Use a DeviseActions enum to keep things tidy

NOTE (Oct 23, 2016): This is outdated. If you’re using Rails 4.1+, it’s cleaner to just use ActiveRecord::Enum.

On my wish list was avoiding vague hardcoded strings like ‘edit’ or ‘new’ scattered throughout the source.

I used the classy_enums gem to enforce a list of valid action names.

After installing the gem, use the generator to create the enum:

(Yeah, probably overkill but it keeps things in the source and database tidy.)


Next create somewhere to log the data

Create the model DeviseUsageLog.

action is the DeviseAction enum. Make the connection between the model and enum by adding the following to model/devise_usage_log.rb:

Allow action to be null since we don’t want potential problems to impact the user. This is the same reason the User and DeviseUsageLog models have not been connected through a ‘belongs_to’ and ‘has_many’. The tracking and logging should have as little impact as possible on the application.

Warning – this table that’s going to grow fast! Make sure to set-up a task to periodically archive and truncate.


Add the ability to control the level of tracking

We need an application configuration variable that sets the amount of tracking being done. The options are :none, :all and :login. Not setting the variable is the same as :none.

Add the following line in each of the three environment config files: development.rb, test.rb, production.rb.


And finally – log the tracked data

Write the DeviseUsageLog.log method we called in the Devise controllers.

In model/devise_usage_log.rb:

In model/user.rb:


Tracking Reports

The DeviseUsageLog model can now be used to list out the Devise activity anyway you want.

One example, is the report I added to the Admin tab of jehughes/rails4-example. The source can be found in the following places:

Controller: app/controllers/devise_usage_log_controller.rb
Model: app/models/devise_usage_log.rb
Views: app/views/devise_usage_log

Or a rake task like lib/tasks/devise_usage.rake.

(Decided not to list out all of the details here – please ask if you have a question.)

Any thoughts, comments, questions are welcome. Did you find this useful? Have a suggestion for a different way to track Devise?