Object stored in Rails session becomes a String?

Deadly 提交于 2019-12-22 04:16:16

问题


Normally I wouldn't store objects in a Rails session but I'm using a library that requires this. I've run into a very strange issue where a stored object appears as a String after redirect.

To reproduce I've created a sample Rails 4.1 app

$ rails new session-test

Added a test controller:

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

setup routes:

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

Then I fire up Rails

$ bundle exec rails server

and hit localhost:3000/home/from in the browser:

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'

I have no idea why this object is getting translated as a String...

It appears to have to do with the session store type of cookie_store because if I change

session_store.rb from

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

to

Rails.application.config.session_store :cache_store

it works!

Any ideas?


回答1:


You can't store objects in the Rails session. It's a key-value store that only accepts strings because, more often than not, it's packaged up and sent to the client as an encrypted cookie.

It's not a dumping ground for things you might need. Pay attention to how much junk you cram in there because the more you lean on the session, the larger the cookie is that the client will have to sling back to your server for every request.

It's worth observing the headers in your browser's network inspection tool to see how heavy a footprint your requests have.

If you really do need to persist something in there, use a string-friendly encoding format like JSON to be sure you can get the data back out in a usable format.

I'd be very hesitant to use the cache_store as well, that doesn't get shared across different instances of your application. Ruby objects only exist within the context of a single process, so other requests, which more often than not will hit some random process, will not be able to make use of this as easily.

The default cookie store is the most reliable. The others that share between processes are dependent on additional services being operational (Memcached, Redis, etc.) but most of those dictate a strings-only policy as well.




回答2:


Fix is to perform serialization and deserialization explicitly, manually.

e.g.

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

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

For shopify_app gem, see file changes in pull request https://github.com/Shopify/shopify_app/pull/90/files and apply accordingly to your existing app.




回答3:


I had the same problem with my Shopify app, and spent a lot of time debugging it. Based on tadman's accurate if not dogmatic explanation, I was able to work around it by Marshalling the session object. It only required 3 lines of code to change:

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)

I posted this on the Shopify forum and expect they'll release an update soon. For what it's worth, I think the old way, while philosophically "wrong", worked correctly in every version of Rails up to 4.1.



来源:https://stackoverflow.com/questions/22978704/object-stored-in-rails-session-becomes-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!