Posted over 6 years ago. Visible to the public.

How to fix: Session hash does not get updated when using "merge!"

tl;dr: Do not use merge! for session hashes. Use update instead.

Outline

Let's assume you're modifying the Rails session. For simplicity, let's also assume your session is empty when you start (same effect when there is data):

Copy
# In our example, we're in a Rack middleware request = Rack::Request.new(env) request.session.merge! :hello => 'Universe' request.session => {}

Wat?

Even worse: When you inspect your request.session like above (e.g. in a debugger shell, or just in your code) any subsequent request.session.merge! will work! Don't stop reading yet, this is not the fix. ;)

What's going on

The culprit is the ActionController::Session::AbstractStore::SessionHash class (session is of that type in your Rails application, but also in Rack middleware):

Copy
class SessionHash < Hash # ... def update(hash) load_for_write! super end

As you can see: While merge! is the same as update on a regular Hash (they are not aliased), update has been changed on SessionHash.

SessionHash#load_for_write! calls load! internally which prepares some data in the session hash. The same happens when you say inspect (which uses load_for_read!) which is why it might seem to be working while looking at the issue.

I'm not sure why SessionHash#merge! is not implemented in a similar fashion, and I don't dare monkey-patching it. Be aware just not to use it – SessionHash#update is what you are looking for.

Note that this happened for me in a Rails 2 application's Rack middleware. While using #merge! might work on regular Rails applications, it is only because the hash was loaded before; but you don't really have a guarantee that this happened.

On Rails 4 applications the issue is similar. Assigning Symbol keys via merge! will not work, while String work. To avoid that, use update on Rails 4, too.

Does your version of Ruby on Rails still receive security updates?
Rails LTS provides security patches for old versions of Ruby on Rails (3.2 and 2.3).

Owner of this card:

Avatar
Arne Hartherz
Last edit:
3 months ago
by Besprechungs-PC
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses cookies to improve usability and analyze traffic.
Accept or learn more