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 keyroot
. - If
root
key is passed orActiveRecord::Base.include_root_in_json = true
is set totrue
, 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
Subscribe to Ruby in Rails
Get the latest posts delivered right to your inbox
