Rails: how to show user's “last seen at” time?

前端 未结 2 459
北恋
北恋 2021-01-31 10:17

I\'m using devise which stores current_sign_in_at and last_sign_in_at datetimes.

But lets say a user logged in a month ago but last vie

相关标签:
2条回答
  • 2021-01-31 10:32

    How about this:

    1. Create a migration to add a new field to users to store the date and time the user was last seen:

      rails g migration add_last_seen_at_to_users last_seen_at:datetime
      
    2. Add a before action callback to your application controller:

      before_action :set_last_seen_at, if: proc { user_signed_in? }
      
      private
      def set_last_seen_at
        current_user.update_attribute(:last_seen_at, Time.current)
      end
      

    This way, on every request (i.e. activity) that the current user performs, his/her last seen at attribute is updated to the current time.

    Please note, however, that this may take up some of your app's resources if you have many users who are logged in, because this will execute before every controller action requested by someone who is logged in.

    If performance is a concern, consider adding the following throttle mechanism to step 2 (in this example, throttling at 15 minutes):

    before_action :set_last_seen_at, if: proc { user_signed_in? && (session[:last_seen_at] == nil || session[:last_seen_at] < 15.minutes.ago) }
    
    private
    def set_last_seen_at
      current_user.update_attribute(:last_seen_at, Time.current)
      session[:last_seen_at] = Time.current
    end
    
    0 讨论(0)
  • 2021-01-31 10:40

    To improve performance of the previous answer:

    • don't use session, as user already loaded with warden and all the attributes are accessible
    • update_attribute runs callbacks and updates updated_at attribute, and update_column not
    • to improve performance, better to use background workers, like ActiveJob/Resque/Sidekiq
    • to prevent from the high DB locking, better to create a seperate table, associated with users table, and write accesses there

    Updated code:

    before_action :set_last_seen_at, if: proc { user_signed_in? && (user.last_seen_at.nil? || user.last_seen_at < 15.minutes.ago) }
    
    private
    def set_last_seen_at
      current_user.update_column(:last_seen_at, Time.now)
    end
    

    Devise plugin makes similar behaviour happen (just last seen, without optimizations): https://github.com/ctide/devise_lastseenable

    0 讨论(0)
提交回复
热议问题