1

I have 2 models:

Store has_many :dishes

Dish belong_to :store

and I use session to store my Cart:

session[:cart] ||= Cart.new

class Cart
  attr_reader :items, :key_items
  def initialize
    @items = Hash.new
    @key_items = Hash.new
  end

  def add_dish(dish)
    #binding.pry
    if @key_items[dish.store_id].nil?
      @items[dish.store_id] = Array.new
      @key_items[dish.store_id] = dish.store
    end

    current_item = @items[dish.store_id].find{|item| item.dish == dish}

    if current_item
       current_item.increment_quantity
    else
      @items[dish.store_id] << CartItem.new(dish)
    end
  end
end

if @key_items[dish.store_id] = dish.store, the session[:cart] dump will be crashed like below:

{"cart"=>
  #<Cart:0x007fa8742deeb0
   @items=
    {1=>
      [#<CartItem:0x007fa8742dedc0
        @dish=
         #<Dish id: 1, store_id: 1, name: "meat", count: 30, remaining_count: 30, price_cents: 1100, price_cents_currency: "CNY", image: nil, description: nil, created_at: "2012-10-11 07:38:26", updated_at: "2012-10-11 07:38:26">,
        @new_record=false>]},
   @quantity=1>,
 :@key_items=>
  {1=>
    #<Store id: 1, name: "ITChef", created_at: "2012-10-11 07:38:26", updated_at: "2012-10-11 07:38:26", start_price_cents: 2500, start_price_cents_currency: "CNY", fare_cents: 800, fare_cents_currency: "CNY">}}

and if @key_items[dish.store_id] = Store.find_by_id(dish.store_id), the dump is right like below:

{"cart"=>
  #<Cart:0x007f9ffc2dc780
   @items=
    {1=>
      [#<CartItem:0x007f9ffc2dc6b8
        @dish=
         #<Dish id: 1, store_id: 1, name: "meat", count: 30, remaining_count: 30, price_cents: 1100, price_cents_currency: "CNY", image: nil, description: nil, created_at: "2012-10-11 07:38:26", updated_at: "2012-10-11 07:38:26">,
        @quantity=1>]},
   @key_items=
    {1=>
      #<Store id: 1, name: "IT厨房", created_at: "2012-10-11 07:38:26", updated_at: "2012-10-11 07:38:26", start_price_cents: 2500, start_price_cents_currency: "CNY", fare_cents: 800, fare_cents_currency: "CNY">}>,
 :@stale_state=>nil}

why?

i keep trace to rails

   39: def set_session(env, session_id, new_session, options)
    40:   with_lock(env, false) do
    41:     @pool.set session_id, new_session, options
 => 42:     session_id
    43:   end
    44: end


[1] pry(#<ActionDispatch::Session::RedisStore>)> new_session
=> {"cart"=>
  #<Cart:0x007fce3f09f3c0
   @items=
    {1=>
      [#<CartItem:0x007fce3f0e1338
        @dish=
         #<Dish id: 2, store_id: 1, name: "糖醋里脊", count: 30, remaining_count: 30, price_cents: 2250, image: nil, description: nil, created_at: "2012-10-17 06:36:59", updated_at: "2012-10-17 06:36:59">,
        @quantity=1>]},
   @key_items=
    {1=>
      #<Store id: 1, name: "it厨房", start_price_cents: 3400, fare_price_cents: 1000, average_time: nil, announcement: nil, image: "it.jpg", is_active: true, created_at: "2012-10-17 06:36:59", updated_at: "2012-10-17 06:36:59">}>,
 "_csrf_token"=>"ZEx7qGOrjq7jra/NtXkm96YCj2DrY1CHkzUHqhvqTns="}

and

[2] pry(#<ActionDispatch::Session::RedisStore>)> @pool.get session_id
=> {"cart"=>
  #<Cart:0x007fce3f9e92c8
   @items=
    {1=>
      [#<CartItem:0x007fce3f9e94d0
        @dish=
         #<Dish id: 2, store_id: 1, name: "糖醋里脊", count: 30, remaining_count: 30, price_cents: 2250, image: nil, description: nil, created_at: "2012-10-17 06:36:59", updated_at: "2012-10-17 06:36:59">,
        @quantity=:@new_record>]},
   @key_items=false>,
 1=>
  {1=>
    #<Store id: 1, name: "it厨房", start_price_cents: 3400, fare_price_cents: 1000, average_time: nil, announcement: nil, image: "it.jpg", is_active: true, created_at: "2012-10-17 06:36:59", updated_at: "2012-10-17 06:36:59">}}

so must be some wrong in the marshal!

lsaturn
  • 145
  • 1
  • 11
  • Store and Dish have used the Money-Rails Gem, is that affect? – lsaturn Oct 17 '12 at 07:40
  • I think the different between dish.store and Store.find_by_id(dish.store_id) is that Store.find_by_id(dish.store_id) have the object information neither dish.store, so session knows how to marshal? – lsaturn Oct 17 '12 at 13:39

2 Answers2

0

Are you getting ActionController::Session::CookieStore::CookieOverflow ?

You can save limited data into the session (Max 3KB) so i'll suggest instead of saving all the object just save it's primary key i.e. id

I mean saving 1 instead of #<Dish id: 1, store_id: 1, name: "meat", count: 30, remaining_count: 30, price_cents: 1100, price_cents_currency: "CNY", image: nil, description: nil, created_at: "2012-10-11 07:38:26", updated_at: "2012-10-11 07:38:26">

Salil
  • 46,566
  • 21
  • 122
  • 156
  • i use Application.config.session_store :active_record_store.i know your meaning.i'll do like that,but i want to know why this happen – lsaturn Oct 17 '12 at 07:53
0

The reason could be that dish.store is an instance of Association actually, not an instance of Store. @stale_state is an variable of Association.

However, Store.find_by_id(dish.store_id) returns a real Store object.

Anyway, it is a bad practice to store those data in sessions.

Yanhao
  • 5,264
  • 1
  • 22
  • 15
  • [1] pry(#)> Store.find_by_id(1) => # [2] pry(#)> dish.store => #.They are all the same – lsaturn Oct 17 '12 at 13:37
  • When you print out the objects in console, object#inspect is called. But session serializes and deserialize data with Marshal. Try `Marshal.dump(Store.find_by_id(1))` and `Marshal.dump(dish.store)`, you'll see the difference. – Yanhao Oct 17 '12 at 15:06
  • I tried and they are all the same. I find this article,http://stackoverflow.com/questions/4705867/rails-doesnt-load-classes-on-deserializing-yaml-marshal-objects, I think the reason maybe is that the Marshal don't know how to serialize and deserialize without object info – lsaturn Oct 18 '12 at 02:39