I’ve talked about Active Model Serializers here and Jbuilder there. Now, I’d like to share with you how you can serialize your models in JSON without using any external gem, just Plain Old Ruby Objects.
We’re going to build yet another simple Ruby on Rails application that will generate JSON for TV Shows and their episodes.
Source Code
Setup the application
Let’s get started.
rails new presenters_tuto
And generate our models/controllers :
rails g resource tv_show name:string rating:integer seasons_count:integer rails g resource season position:integer tv_show_id:integer rails g resource episode name:string season_id:integer
Add the relations between our models :
# app/models/tv_show.rb
class TvShow < ActiveRecord::Base
has_many :seasons
end
# app/models/season.rb
class Season < ActiveRecord::Base
belongs_to :tv_show
has_many :episodes
end
# app/models/episode.rb
class Episode < ActiveRecord::Base
belongs_to :season
end
And migrate :
rake db:migrate
Add an index action to the TvShows Controller :
# app/controllers/tv_shows_controller.rb
class TvShowsController < ApplicationController
def index
end
end
Sample Data
Finally, here’s some sample data :
# db/seeds.rb
suits = TvShow.create! name: 'Suits', rating: 9, seasons_count: 4
s01 = suits.seasons.create! position: 1
s01.episodes.create! name: 'Pilot'
s01.episodes.create! name: 'Errors and Omissions'
s01.episodes.create! name: 'Inside Track'
PORO Presenters
Now it’s time to create our JSON presenters. To do that, we’re going to create a folder called ‘presenters’ under ‘app’. For each model, we will create a model presenter to format the JSON. We’re going to build those presenters on top of ‘as_json’.
First, we need a parent presenter to remove some redundant code from the children :
# app/presenters/presenter
class Presenter
def initialize(object)
@object = object
end
def as_json
raise 'as_json called on parent.'
end
end
Then, we can create a presenter for a TV show :
# app/presenters/tv_show_presenter.rb
class TvShowPresenter < Presenter
def as_json(*)
{
name: @object.name,
rating: @object.rating,
seasons_count: @object.seasons_count
}
end
end
And a presenter for a list of tv shows :
# app/presenters/tv_shows_presenter.rb
class TvShowsPresenter < Presenter
def as_json(*)
{
tv_shows: @object.map { |o| TvShowPresenter.new(o) }
}
end
end
We can now use this in TvShowsController :
class TvShowsController < ApplicationController
def index
render json: TvShowsPresenter.new(TvShow.all)
end
end
And we get :
As you can see, it’s very easy to create your own presenters.
Let’s see how we can add our nested models. We need to create ‘app/presenters/episode_presenter.rb’ and ‘app/presenters/season_presenter.rb’.
# app/presenters/season_presenter.rb
class SeasonPresenter < Presenter
def as_json(*)
{
position: @object.position,
epiodes: @object.episodes.map {|e| EpisodePresenter.new(e) }
}
end
end
# app/presenters/episode_presenter.rb
class EpisodePresenter < Presenter
def as_json(*)
{
name: @object.name
}
end
end
And update the TvShow presenter to include seasons :
# app/presenters/tv_show_presenter.rb
class TvShowPresenter < Presenter
def as_json(*)
{
name: @object.name,
rating: @object.rating,
seasons_count: @object.seasons_count,
seasons: @object.seasons.map {|s| SeasonPresenter.new(s) }
}
end
end
And we’ll get a beautiful json :
The End
As you can see, implement your own clean JSON builders is not that hard. However, I would recommend using great gems like Active Model Serializers or Jbuilder to build your JSON. This article is more for knowledge purposes. If you have very specific needs, you can now build your own JSON building solution based on this tutorial.