【问题标题】:Rails: how to show user's "last seen at" time?Rails:如何显示用户的“最后一次看到”时间?
【发布时间】:2014-01-16 06:20:47
【问题描述】:

我正在使用存储 current_sign_in_atlast_sign_in_at 日期时间的设计。

假设用户在一个月前登录但最后一次查看页面是在 5 分钟前?

有什么方法可以显示(“用户最后一次出现在 5 分钟前”)。

【问题讨论】:

    标签: ruby-on-rails ruby ruby-on-rails-3 devise ruby-on-rails-4


    【解决方案1】:

    这个怎么样:

    1. 创建迁移以向用户添加一个新字段以存储用户上次出现的日期和时间:

      rails g migration add_last_seen_at_to_users last_seen_at:datetime
      
    2. 为您的应用程序控制器添加一个操作前回调:

      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
      

    这样,在当前用户执行的每个请求(即活动)上,他/她最后一次看到的属性都会更新为当前时间。

    但是请注意,如果您有很多用户登录,这可能会占用您应用的一些资源,因为这将在登录用户请求的每个控制器操作之前执行。

    如果性能是一个问题,请考虑将以下限制机制添加到第 2 步(在本示例中,限制为 15 分钟):

    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
    

    【讨论】:

    • 谢谢查尔斯。这是我关心的问题——有没有办法以尽可能少的资源使用来实现这一点?每个页面视图对数据库的更新将太多:)
    • 这里没有必要使用会话变量进行节流。直接使用current_user.last_seen_at 值即可。
    • @Lorenz 否。current_user 已经从数据库中获取,同时还有 last_seen_at 值。
    • @Lorenz 你的想法是正确的;但是,这是我们正在比较的两个时间戳。 x &lt; 15.minutes.ago? 读起来像英文,所以令人困惑,但它的真正含义是“这个时间戳 x 是否小于 15 分钟前的时间戳”。这与询问“这是否超过 15 分钟前”相同,因为更早的时间戳会更小。希望这可以解决问题:)
    • 最好使用update_column 而不是update_attribute - 否则您将更新updated_at 并触发用户模型上定义的所有回调,这很可能不是所需的行为
    【解决方案2】:

    提高上一个答案的性能:

    • 不要使用 session,因为用户已经加载了warden,并且所有属性都可以访问
    • update_attribute 运行回调并更新 updated_at 属性,update_column 不运行
    • 为了提高性能,最好使用后台工作人员,例如 ActiveJob/Resque/Sidekiq
    • 为了防止高 DB 锁定,最好创建一个单独的表,与 users 表关联,并在那里进行写访问

    更新代码:

    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 插件使类似的行为发生(刚刚看到,没有优化):https://github.com/ctide/devise_lastseenable

    【讨论】:

    • 很好的发现。更多改进:before_action :set_last_seen_at, if: -&gt; { user_signed_in? &amp;&amp; (current_user.last_seen_at.nil? || current_user.last_seen_at &lt; 15.minutes.ago) }。似乎最好使用Time.zone.now 而不是Time.now
    猜你喜欢
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-03
    • 2014-03-27
    • 2015-01-14
    • 1970-01-01
    相关资源
    最近更新 更多