Because we still have applications using Rails 3.2, and it’s really such a pain to upgrade apps with so many complicated logics like us.
ActiveSupport::JSON module provides a super simple API composed by two methods:
ActiveSupport::JSON.encode(object) takes a Ruby object as value and returns a JSON-encoded string. On the opposite, ActiveSupport::JSON.decode(string) takes a JSON-encoded string and returns the corresponding Ruby object.
As I mentioned in my previous article, we should implement two more methods to make our custom object serialization work: to_json and self.json_create. Do we have to do that if we are using Rails a.k.a ActiveSupport::JSON?
The common usage of serializing custom objects in Rails is serializing them to a string field stored in database. And we could achieve that with writing our own custom serializer for custom objects. I won’t cover this in this post, maybe in the near future I will do that.
So, like the previous post, we will pay some attention on the performance of serialization in Rails.
ActiveSupport depends on multi_json gem, which is a simple library that allows you to semalessly provide multiple JSON backends with intelligent defaulting. And ActiveSupport::JSON uses json as its default engine, we could know that by ActiveSupport::JSON.engine # => MultiJson::Adapters::JsonGem.
Then let’s do some benchmarking, eg: setting oj as ActiveSupport’s default engine.
And the result may just blow your mind. We already specify our engine to Oj, right? They are supposed to behave like each other . What’s wrong with active_support?
The root cause is ActiveSupport’s implementation problem. In active_support/core_ext/object/to_json.rbfile :
Did you see the to_json method? It will use ActiveSupport::JSON.encode every time with hard-coded guaranteed.
This monkeypatch was introduced to fix a problem (see comments above the code), but also caused another pain: If you are currently using the JSON/oj/whatever gem adapter with Rails (AS::JSON::Encoding), and you have been calling object#to_json, you are actually using Rail’s pure Ruby JSON encoder. And this explains why the performance suck so much.
Then how to fix this? The solution is quite simple: apply a similar change as the one in active_support/core_ext/object/to_json.rb, monkeypatch to override to_json method again, let it use Oj to do encoding job.
Rails 4.1 removes multi_json dependency, and the previous patch/gem is unnecessary and will no longer work. Instead, if you want to use oj to deal with JSON, use the oj_mimic_jsongem with oj in your Gemfile to have Oj mimic the JSON gem and be used in its place by ActiveSupport JSON handling: