【发布时间】:2014-01-16 06:20:47
【问题描述】:
我正在使用存储 current_sign_in_at 和 last_sign_in_at 日期时间的设计。
假设用户在一个月前登录但最后一次查看页面是在 5 分钟前?
有什么方法可以显示(“用户最后一次出现在 5 分钟前”)。
【问题讨论】:
标签: ruby-on-rails ruby ruby-on-rails-3 devise ruby-on-rails-4
我正在使用存储 current_sign_in_at 和 last_sign_in_at 日期时间的设计。
假设用户在一个月前登录但最后一次查看页面是在 5 分钟前?
有什么方法可以显示(“用户最后一次出现在 5 分钟前”)。
【问题讨论】:
标签: ruby-on-rails ruby ruby-on-rails-3 devise ruby-on-rails-4
这个怎么样:
创建迁移以向用户添加一个新字段以存储用户上次出现的日期和时间:
rails g migration add_last_seen_at_to_users last_seen_at:datetime
为您的应用程序控制器添加一个操作前回调:
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 值即可。
current_user 已经从数据库中获取,同时还有 last_seen_at 值。
x < 15.minutes.ago? 读起来像英文,所以令人困惑,但它的真正含义是“这个时间戳 x 是否小于 15 分钟前的时间戳”。这与询问“这是否超过 15 分钟前”相同,因为更早的时间戳会更小。希望这可以解决问题:)
update_column 而不是update_attribute - 否则您将更新updated_at 并触发用户模型上定义的所有回调,这很可能不是所需的行为
提高上一个答案的性能:
update_attribute 运行回调并更新 updated_at 属性,update_column 不运行更新代码:
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: -> { user_signed_in? && (current_user.last_seen_at.nil? || current_user.last_seen_at < 15.minutes.ago) }。似乎最好使用Time.zone.now 而不是Time.now。