Skip to content

Instantly share code, notes, and snippets.

@jimweirich
Created February 28, 2011 17:06
Show Gist options
  • Select an option

  • Save jimweirich/847634 to your computer and use it in GitHub Desktop.

Select an option

Save jimweirich/847634 to your computer and use it in GitHub Desktop.
# This is a fragment of code from action_controller/request.rb that handles sessions.
# (this is Rails 2.3.11 if that matters).
# It is obvious from the first method that a session is expected to be a hash.
def session
@env['rack.session'] ||= {}
end
def session=(session) #:nodoc:
@env['rack.session'] = session
end
# But, if session is a hash, what is "session.destroy" expected to do?
# I'm confused.
def reset_session
session.destroy if session
self.session = {}
end
# We are actually hitting the session.destroy line when session is a normal looking hash.
# I don't understand how this code is even correct.
@yellow5

yellow5 commented Feb 28, 2011

Copy link
Copy Markdown

Taking a peek at this thread..

https://rails.lighthouseapp.com/projects/8994/tickets/6440-session-reset-undefined-method-destroy-for-hash

It points to this file being the potential culprit...

actionpack-2.3.11/lib/action_controller/session/abstract_store.rb

@josevalim

Copy link
Copy Markdown

The rails session is not expected to be an ActiveRecord::Base object. Even when the session is ActiveRecord based, we have an object that wraps an instance of ActiveRecord. So, what is happening?

Rack initializes the session as a hash but it is later replaced by a SessionHash object (which responds to destroy) in the session middleware:

https://github.com/rails/rails/blob/2-3-stable/actionpack/lib/action_controller/session/abstract_store.rb#L208-211

After you reset the session, it sets a hash back. The obvious bug here is that if you call reset_session twice, it will raise an error. It has been fixed in Rails 3-0-stable and master (but it seems it was not backported):

https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb#L220-224

The session middleware explicitly checks if the session is a hash, and, if so, it serializes it completely back. When the SessionHash object is in the session, it tries to be a bit smarter and just serializes it back if something was written and so on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment