Override as_json in Rails

When we call as_json on ActiveRecord model object, it returns json of attributes on model by calling as_json. We can override as_json method and add extra attributes, rename keys, add values of methods on object to the json returned.

Let’s take an example to understand this. Let’s say we have a model Post as given below.

class Post < ApplicationRecord {
  :id => :integer,
  :title => :string,
  :description => :text,
  :user_id => :integer,
  :published_at => :datetime
}
# Fetching last post just for this example.
post = Post.last

The post has values as given below.

#<Post:0x007f9212a74440> {
               :id => 1,
            :title => "Override as_json in Rails",
      :description => "We can override as_json method and add extra attributes, rename keys, add values of methods on object to the json returned.",
           user_id => 1,
     :published_at => Tue, 25 Jun 2019 07:19:30 UTC +00:00
}

Now, calling as_json returns hash as given below.

{
               :id => 1,
            :title => "Override as_json in Rails",
      :description => "We can override as_json method and add extra attributes, rename keys, add values of methods on object to the json returned.",
           user_id => 1,
     :published_at => Tue, 25 Jun 2019 07:19:30 UTC +00:00
}

Let’s look at the source code of as_json method.

# File activemodel/lib/active_model/serializers/json.rb, line 89
def as_json(options = nil)
  root = if options && options.key?(:root)
    options[:root]
  else
    include_root_in_json
  end

  if root
    root = model_name.element if root == true
    { root => serializable_hash(options) }
  else
    serializable_hash(options)
  end
end

This method works as given below.

  • It checks, if options passed has key root.
  • If root key is passed or ActiveRecord::Base.include_root_in_json = true is set to true, it will include root node (model name) in resultant hash / json.
  • At the end it calls serializable_hash with options that uses ActiveModel::Serializer to serialize the model attributes.

Override as_json method on ActiveRecord model object

Let’s say, we want to add user_name as well in the response corresponding to user_id of the post.

We can achive this by overriding as_json key in the response.

class Post
  belongs_to :user

  def as_json(options = {})
    super(options).merge({
      'user_name' => user.name
    })
  end
end
  • Here, we have overriden as_json method
  • Called super(options) to fetch json that would have been returned otherwise.
  • Merged user_name key-value in the resultant hash / json.

Rename key on as_json response of ActiveRecord model object

Similarly, we can rename key from the response of as_json, by overriding the method.

class Post
  belongs_to :user

  def as_json(options = {})
    hash = super(options)
    hash.delete(post_title: hash.delete('title'))
  end
end

Here, we have renamed the title key in the resultant response to post_title.

When json generation gets complicate with overriding as_json method on ActiveRecord model object, it is better to use jbuilder to generate json response for APIs

References