See if User is online using Devise in Ruby on Rails

Recently, I needed to figure out if a user was active(online) on my site. Because I hadn't done this before, I Googled for inspiration 🌈 but found little success 🙃. The majority of posts on Stack Overflow and blogs were variations of the same solution:

1) Add a last_online timestamp column to your User model, then define a scope for user called online_now.

Meaning, add new column to store on every timestamp the user is active/online. Then make a query(scope) from database which user that last active 2-10 minutes ago and display to the view.

This may take up some of your app's resources if you have many users who are logged in, because this will execute(update column & database query) before every controller action requested by someone who is logged in.

I think this process is slow.

Pretty old gems.

3) When someone has logged in, you can push him into an array, if someone has logged out, just remove him from the array.

I think last time I use this trick is on my Computer Science studies 😂 at universities long time ago.

4) WebSocket & Redis

If you're bothered by making a trip to database on every. single. http. request. only to have some small window where you can sort of assume that a user is online; There have an alternate solution.

Using websockets and redis it's possible to reliably get a user's online status up to the millisecond without making a billion costly writes to disk.

Unfortunately, it requires a good bit more work and has two additional dependencies.

There is one article that explains well how to use this solution if you are interested.

But probably not my choice for a simple project.

So, What else ?

Well, this solution is related to Devise.

When we create a User Model based on Devise;

rails generate devise User

Devise will create updated_at column with a datetime data type.

This is good tho. We can utilize already column from Devise instead of creating a new column like previous solution.

Whenever the current_user does any action, his updated_at will be set as Time.now.

#application_controller.rb

after_action :update_user_online, if: :user_signed_in?

private

def update_user_online
  current_user.try :touch
end

And we will just say that the user is online if he was updated_at during the last 2.minutes or 1.minutes

#user.rb

def online?
  updated_at > 2.minutes.ago
end

Now we can get true or false if we make a call like @user.online?

#users/show.html.erb

<%= @user.online? %>

This is one of the best and simple solution I get when doing research and a little bit of experimentation.

I am very happy 😇 if you can share to me other tricks that is better than this.

The end

resources:

25