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.lastThe 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
endThis method works as given below.
- It checks, if
optionspassed has keyroot. - If
rootkey is passed orActiveRecord::Base.include_root_in_json = trueis set totrue, it will include root node (model name) in resultant hash / json. - At the end it calls
serializable_hashwith 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_jsonmethod - Called
super(options)to fetch json that would have been returned otherwise. - Merged
user_namekey-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
endHere, 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