Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails 4 upgrade JSON::ParseError for old sessions

After upgrading to Rails 4.1.4 from Rails 3.2, accessing the application with an existing session (from the older Rails 3.2 version) causes an internal server error. backtrace:

JSON::ParserError - 795: unexpected token at {
I"session_id:ETI"%fa78a4ee07ac952c9b034ebc6199f30b;':
  /Users/.../.rvm/rubies/ruby-2.1.0/lib/ruby/2.1.0/json/common.rb:155:in `parse'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:388:in `load'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:428:in `deserialize'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:183:in `verify_and_upgrade_legacy_signed_message'
  actionpack (4.1.4) lib/action_dispatch/middleware/cookies.rb:550:in `[]'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:114:in `get_cookie'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:90:in `block in unpacked_cookie_data'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/abstract_store.rb:51:in `stale_session_check!'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:89:in `unpacked_cookie_data'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:83:in `block in extract_session_id'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/abstract_store.rb:51:in `stale_session_check!'
  actionpack (4.1.4) lib/action_dispatch/middleware/session/cookie_store.rb:82:in `extract_session_id'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:49:in `block in []'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:48:in `[]'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:70:in `id'
  rack (1.5.2) lib/rack/session/abstract/id.rb:282:in `current_session_id'
  rack (1.5.2) lib/rack/session/abstract/id.rb:288:in `session_exists?'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:152:in `exists?'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:172:in `load_for_read!'
  actionpack (4.1.4) lib/action_dispatch/request/session.rb:89:in `[]'
  warden (1.2.3) lib/warden/session_serializer.rb:30:in `fetch'
  warden (1.2.3) lib/warden/proxy.rb:212:in `user'
  warden (1.2.3) lib/warden/proxy.rb:318:in `_perform_authentication'
  warden (1.2.3) lib/warden/proxy.rb:104:in `authenticate'
  warden (1.2.3) lib/warden/proxy.rb:114:in `authenticate?'
  devise (3.2.4) lib/devise/rails/routes.rb:460:in `block in constraints_for'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:38:in `block in matches?'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:36:in `matches?'
  actionpack (4.1.4) lib/action_dispatch/routing/mapper.rb:45:in `call'
  actionpack (4.1.4) lib/action_dispatch/journey/router.rb:71:in `block in call'
  actionpack (4.1.4) lib/action_dispatch/journey/router.rb:59:in `call'
  actionpack (4.1.4) lib/action_dispatch/routing/route_set.rb:678:in `call'
  ...

I tried to change the session cookie key name, but it seems to be stuck on session_id.

# initializers/session_store.rb
MyApp::Application.config.session_store :cookie_store, key: 'myapp_session'

Please help! A great solution would also be to delete all session cookies before they hit the rails middleware, but i have no idea how to do that..

like image 527
Yossi Shasho Avatar asked Jul 30 '14 08:07

Yossi Shasho


People also ask

Is it safe to use JSON in rails?

These JSON gem APIs are meant for serializing and deserializing arbitrary Ruby objects and are generally unsafe. Historically, Rails had some compatibility issues with the JSON gem.

What has changed with the JSON encoder in rails 4?

The JSON encoder in Rails 4.1 has been rewritten to take advantage of the JSON gem. For most applications, this should be a transparent change. However, as part of the rewrite, the following features have been removed from the encoder:

How do the JSON GEM APIs work in rails?

The JSON gem APIs will function as normal, but they will not have access to any Rails-specific features. For example: The JSON encoder in Rails 4.1 has been rewritten to take advantage of the JSON gem. For most applications, this should be a transparent change.

What happened to multijson in rails 4?

There are a few major changes related to JSON handling in Rails 4.1. MultiJSON has reached its end-of-life and has been removed from Rails. If your application currently depends on MultiJSON directly, you have a few options: Add 'multi_json' to your Gemfile. Note that this might cease to work in the future


2 Answers

Found the answer here: https://github.com/rails/rails/issues/15111

My settings had

# initializers/cookie_serializer.rb
Rails.application.config.action_dispatch.cookies_serializer = :json

I changed it to

Rails.application.config.action_dispatch.cookies_serializer = :hybrid

And that did the trick

like image 68
Yossi Shasho Avatar answered Sep 18 '22 09:09

Yossi Shasho


If you're comfortable with changing your secret key, then it will solve the problem, and I can confirm that people with old cookies will not encounter a 500 error.

Run rake secret to generate a new secret.

If you've implemented config/secrets.yml, put the new secret in there. Otherwise, if you still have your secret in config/initializers/secret_token.rb, put it in there.

Leave your config/initializers/session_store.rb file alone -- you don't need to change it.

In config/initializers/cookie_store.rb, change it to :json:

# Be sure to restart your server when you modify this file.

Rails.application.config.action_dispatch.cookies_serializer = :json

I can confirm that this works, even when your browser is storing an old session cookie. By changing the secret, when someone with an old session cookie visits your site, the server simply ignores the old session state and creates a new session. No 500 error.

like image 20
ctc Avatar answered Sep 21 '22 09:09

ctc