librelist archives

« back to archive

Rails 4.1 and JSON encoder

Rails 4.1 and JSON encoder

From:
Matthijs Langenberg
Date:
2014-09-26 @ 19:35
I might be late to the party, but I just upgraded a Rails app from 4.0 to
4.1, and I stumbled upon a change that might be interesting to other
Sidekiq users.

The Rails guides inform about changes in JSON handling:

http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#changes-in-json-handling

"Rails 4.1 fixed these issues by isolating its own encoder from the JSON
gem."

Sidekiq uses the JSON gem under the hood. I believe that Rails 4.0
overrides certain methods in such way, that Rails-specific features such as
#as_json are called. When you use Rails 4.1, that is no longer the case.

So when you pass arguments to Worker.perform_async, those arguments may be
serialized in a different way to Worker#perform then you expected before.

To give you a concrete example, the app I work on passes a hash containing
dates (actually ActiveSupport::TimeWithZone instances).

With Rails 4.0 these are passed to Worker#perform in ISO8601 format,
because of ActiveSupport::TimeWithZone#as_json.

With Rails 4.1 they are actually normal stringified dates:

    gem 'rails', '4.0.10'
    gem 'json', '1.8.1'

    require 'rails/all'
    require 'json'
    puts "Rails-" + Rails.version
    Time.zone = 'Amsterdam'
    time = Time.zone.now

    puts time.as_json
    puts JSON.generate([time])

    # OUTPUT:
    # Rails-4.0.10
    # 2014-09-26T21:02:13.094+02:00
    # ["2014-09-26T21:02:13.094+02:00"]

    # Rails-4.1.0
    # 2014-09-26T21:01:51.201+02:00
    # ["2014-09-26 21:01:51 +0200"] !! Broke one of my unit tests.

This might explain it even better:
https://gist.github.com/mlangenberg/6c7319768616251b9886

My current solution is to call #as_json before calling
Worker.perform_async. So Worker.perform_async(args.as_json).

What do you think?

- Matthijs