First, whenever the current_user does any action, his updated_at will be set to Time.now:

# app/controllers/application_controller.rb
after_action :update_user_online, if: :user_signed_in?

private

def update_user_online
  current_user.try :touch
end

Next, we will just say that the user is online if he was updated_at within the last 2.minutes:

# app/models/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?:

# app/views/users/show.html.erb
<%= @user.online? %>

Problems with this approach:

  • you do not want to override the purpose of update_at
  • you WRITE to the database after each request = expensive

Better approach #

Add a separate attribute to the User model:

# terminal
rails g migration add_last_online_at_to_users last_online_at:datetime

“Throttle” writes to the database: do not write last_online_at to the database more than once in 5 minutes:

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  after_action :update_user_online, if: :user_signed_in?

  private

  def update_user_online
    return if session[:last_online_at] && session[:last_online_at] > 5.minutes.ago

    current_user.update!(last_online_at: Time.current)
    session[:last_online_at] = Time.current
  end
end

That’s much better!