November 4, 2014 · rails ruby

ActiveModel::Serializers vs Jbuilder

Jbuilder is a DSL for compose JSON in Ruby. "It’s so cool", that Rails give it us out of the box even in version 4.2. But, I think it’s not a perfect solution. Actually my first expression about Jbuilder was: “Hmmm.. What is this?! Looks like a template, but Ruby insets are everywhere!!” So I think Jbuilder is too complex and unhandy. It's very difficult to use it from outside of controllers. For example if you Rails back-end provide pushes, it will be hard getting JSON from Jbuilder.

So we have a good alternative. It's ActiveModel::Serializers: https://github.com/rails-api/activemodelserializers. It has very simple OO-DSL and you can use it anywhere like other Ruby classes. For example:

class MovieSerializer < ActiveModel::Serializer  
  attributes :title, :year

  has_many :genres
end

MovieSerializer.new(movie_object).to_json  
# => {"movie" => {"title" => "Title", "year" => 2014, "genres" => […]}}

Very fun, isn't? One my colleague someday said that AMS is much slower than Jbuilder. And here is little benchmarking about it.

Benchmarking

I will use Rails 4.1.7 with Jbuilder 2.0 and ActiveModel::Serializers 0.9.0.

There are four different cases that I separated out:

Why I use render method? Because it's the default way to deal with Jbuilder templates. You mostly store your Jbuilder as template in views directory, and much more less use it's standalone through Jbuilder.new/encode. And the opposite ActiveModel::Serializers works pretty well with both variants of usage.

Sources of benchmarks are here: http://goo.gl/in1zbF

Single object with render

➜  ams_vs_jbuilder  rake benchmarks:single_object_with_render
Calculating -------------------------------------  
            jbuilder        24 i/100ms
active_model_serializers  
                           147 i/100ms
-------------------------------------------------
            jbuilder      229.5 (±13.5%) i/s -       1128 in   5.021995s
active_model_serializers  
                         2743.3 (±16.0%) i/s -      13377 in   5.013579s

Comparison:  
active_model_serializers:     2743.3 i/s  
            jbuilder:      229.5 i/s - 11.95x slower

Single object without render

➜  ams_vs_jbuilder  rake benchmarks:single_object_without_render
Calculating -------------------------------------  
            jbuilder       394 i/100ms
active_model_serializers  
                           354 i/100ms
-------------------------------------------------
            jbuilder     5213.9 (±14.0%) i/s -      25610 in   5.003398s
active_model_serializers  
                         4895.9 (±13.5%) i/s -      24072 in   5.010093s

Comparison:  
            jbuilder:     5213.9 i/s
active_model_serializers:     4895.9 i/s - 1.06x slower  

Array of objects with render

➜  ams_vs_jbuilder  rake benchmarks:array_of_objects_with_render
Calculating -------------------------------------  
            jbuilder         4 i/100ms
active_model_serializers  
                            42 i/100ms
-------------------------------------------------
            jbuilder       50.2 (±10.0%) i/s -        252 in   5.073880s
active_model_serializers  
                          448.8 (±8.5%) i/s -       2226 in   4.995827s

Comparison:  
active_model_serializers:      448.8 i/s  
            jbuilder:       50.2 i/s - 8.94x slower

Array of objects without render

➜  ams_vs_jbuilder  rake benchmarks:array_of_objects_without_render
Calculating -------------------------------------  
            jbuilder        36 i/100ms
active_model_serializers  
                            45 i/100ms
-------------------------------------------------
            jbuilder      386.4 (±11.6%) i/s -       1908 in   5.002895s
active_model_serializers  
                          488.1 (±9.8%) i/s -       2430 in   5.026865s

Comparison:  
active_model_serializers:      488.1 i/s  
            jbuilder:      386.4 i/s - 1.26x slower

Conclusion

You can see everything by yourself. Jbuilder wins ActiveModel::Serializers only in standalone variant of usage and only when use transform only single AR object, not an array. But the difference between Jbuilder and AMS in this case only 1.06x, it's very close to calculating error.

And from opposite you can see, that in all another cases Jbuilder is much slower than ActiveModel::Serializers. And it's the real world cases, because Jbuilder is mostly used with render method. And the results with render method are extremely bad for Jbuilder:

I think for now there is really no reason to use Jbuilder. It's very slow, too verbose and too complex for such simple task as transforming objects to JSON. You can use ActiveModel::Serializers and it will be handy and will cover all of your usage cases.

Happy programming with AMS!