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
相关产品推荐
相关产品推荐

