存储在Rails会话中的对象变成了一个String?

时间:2014-04-10 04:32:37

标签: ruby-on-rails session ruby-on-rails-4 shopify ruby-on-rails-4.1

通常我不会在Rails会话中存储对象,但是我使用的是需要它的库。我遇到了一个非常奇怪的问题,即重定向后存储的对象显示为String。

为了重现,我创建了一个示例Rails 4.1应用程序

$ rails new session-test

添加了测试控制器:

class HomeController < ApplicationController
  def index
    logger.debug "session[:customer]: #{session[:customer]}"
    logger.debug "session[:customer].name: #{session[:customer].name}"
  end

  def from
    Struct.new 'Customer', :name, :address
    session[:customer] = Struct::Customer.new 'Dave', '123 Main'
    redirect_to :action => :index
  end
end

设置路线:

Rails.application.routes.draw do
  get 'home/index'
  get 'home/from'
  root 'home#index'
end

然后我启动Rails

$ bundle exec rails server

并在浏览器中点击localhost:3000 / home /:

Started GET "/home/from" for 127.0.0.1 at 2014-04-09 21:20:25 -0700
Processing by HomeController#from as HTML
Redirected to http://localhost:3000/home/index
Completed 302 Found in 18ms (ActiveRecord: 0.0ms)


Started GET "/home/index" for 127.0.0.1 at 2014-04-09 21:20:25 -0700
Processing by HomeController#index as HTML
session[:customer]: #<struct Struct::Customer name="Dave", address="123 Main">
Completed 500 Internal Server Error in 2ms

NoMethodError (undefined method `name' for "#<struct Struct::Customer name=\"Dave\", address=\"123 Main\">":String):
  app/controllers/home_controller.rb:4:in `index'

我不知道为什么这个对象被翻译为String ...

它似乎与cookie_store的会话存储类型有关,因为如果我改变

来自

session_store.rb

Rails.application.config.session_store :cookie_store, key: '_session-test_session'

Rails.application.config.session_store :cache_store

它有效!

有什么想法吗?

3 个答案:

答案 0 :(得分:5)

您无法在Rails会话中存储对象。它是一个只接受字符串的键值存储,因为它经常被打包并作为加密cookie发送给客户端。

它不是您可能需要的东西的倾倒场。注意你在那里塞满了多少垃圾,因为你对会话的依赖程度越大,cookie就越大,客户将不得不为每个请求回到你的服务器。

值得观察浏览器网络检测工具中的标题,看看您的请求占用的空间有多大。

如果您确实需要在其中保留某些内容,请使用类似JSON的字符串友好编码格式,以确保您可以以可用格式恢复数据。

我也非常犹豫使用cache_store,但是不能在应用程序的不同实例之间共享。 Ruby对象只存在于单个进程的上下文中,因此其他请求(通常不会触及某些随机进程)将无法轻易地使用它。

默认的cookie商店是最可靠的。在进程之间共享的其他服务依赖于正在运行的其他服务(Memcached,Redis等),但大多数服务也决定了仅字符串策略。

答案 1 :(得分:4)

修复是手动显式执行序列化和反序列化。

e.g。

# storing...
session[:customer] = (Struct::Customer.new 'Dave', '123 Main').to_yaml

# retrieving...
customer = YAML.load(session[:customer])

对于shopify_app gem,请参阅拉取请求https://github.com/Shopify/shopify_app/pull/90/files中的文件更改,并相应地应用于现有应用。

答案 2 :(得分:0)

我的Shopify应用程序遇到了同样的问题,并花了很多时间调试它。基于tadman的准确,如果不是教条的解释,我能够通过编组会话对象来解决它。它只需要改变3行代码:

login_protection.rb:12:ShopifyAPI :: Base.activate_session(Marshal :: load session [:shopify]) login_protection.rb:25:Marshal :: load session [:shopify]

sessions_controller.rb:13:session [:shopify] = Marshal :: dump(sess)

我在Shopify论坛上发布了此消息,预计他们很快就会发布更新。对于它的价值,我认为旧方法虽然在哲学上是“错误的”,但在每个版本的Rails中都能正常工作,直到4.1。