You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ruby 2.6升级后Devise中last_request_at传字符串致错误,如何转为整数?

解决Ruby 2.6升级后Devise中last_request_at以字符串传递的问题

方案1:修正Devise Timeoutable钩子的类型处理逻辑

Devise默认的timeoutable.rb对字符串类型的时间戳处理存在问题,Time.parse无法解析纯数字格式的时间戳字符串。你可以通过初始化器覆盖这个钩子逻辑:

创建config/initializers/devise_timeoutable_fix.rb,添加以下代码:

Devise::Hooks::Timeoutable.module_eval do
  def timeoutable?(warden)
    scope = warden.scope
    user = warden.user(scope)
    return unless user && user.respond_to?(:timeout_in)

    last_request_at = warden.session(scope)["last_request_at"]
    return unless last_request_at

    # 修正字符串转时间逻辑:先转整数再用Time.at解析
    if last_request_at.is_a? Integer
      last_request_at_time = Time.at(last_request_at).utc
    elsif last_request_at.is_a? String
      last_request_at_time = Time.at(last_request_at.to_i).utc
    end

    last_request_at_time && (Time.now.utc - last_request_at_time) > user.timeout_in
  end
end

方案2:强制Session中last_request_at以整数存储

通过Warden钩子在用户认证后,强制将Session中的last_request_at转换为整数:

在config/initializers/devise.rb中添加:

Warden::Manager.after_set_user do |user, auth, opts|
  scope = opts[:scope] || :user
  # 确保last_request_at始终为整数类型
  if auth.session(scope)["last_request_at"]
    auth.session(scope)["last_request_at"] = auth.session(scope)["last_request_at"].to_i
  end
end

方案3:调整Session序列化方式

Ruby 2.6升级后,部分Rails环境默认将Session序列化方式从Marshal切换为JSON,而JSON会把整数转为字符串。若使用CookieStore,可切换回Marshal序列化(注意:Marshal存在安全风险,仅在信任Session数据的场景使用):

修改config/initializers/session_store.rb:

Rails.application.config.session_store :cookie_store, 
  key: '_your_app_session',
  serializer: :marshal

问题根源

Ruby 2.6升级后,Session序列化机制的变化(如从Marshal切换为JSON)导致存储的时间戳整数被序列化为字符串。而Devise的Timeoutable钩子遇到字符串时,错误地使用Time.parse解析(该方法仅支持日期格式字符串,不支持纯数字时间戳),最终触发argument out of range错误。

内容的提问来源于stack exchange,提问作者Chikki Jabson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 18:30:21