ActiveModel::Serializers
Problem
#as_json in the Model
class SeScorecardCategory < ActiveRecord::Base
def as_json(options={})
attributes.merge({
questions: se_scorecard_questions_asc.as_json(options),
subcategories: subcategories.newest_on_bottom_order.as_json(options)
})
end
end
We can do better!
#as_json in a Presenter
class RequirementsTemplateCategoryPresenter < BasePresenter
attr_accessor :template_category
def initialize(template_category)
@template_category = template_category
end
def as_json(opts={})
template_category.as_json.merge({
template_groups: RequirementsTemplateGroupPresenter.as_collection(template_category.template_groups_root, current_user: opts[:current_user]),
creator_name: template_category.creator.to_s,
created_at_date: template_category.created_at_date,
created_at_time: template_category.created_at_time,
requirement_template_id: template_category.requirement_template.id,
product_category_name: template_category.get_parent_category_name
})
end
end
We can do better!
class BasePresenter
include Rails.application.routes.url_helpers
def self.as_collection(collection, opts={})
collection.map { |object| self.new(object).as_json(opts) }
end
def self.as_presenters_collection(collection)
collection.map { |object| self.new(object) }
end
def link_to(*args, &block)
ApplicationController.helpers.link_to(*args, &block)
end
end
rabl
object @project_group => nil
attributes :id, :name, :project_category_id
node :project_id do |project_group|
project_group.project_category.project.to_param
end
node :created_at_date do |project_group|
project_group.created_at.to_s
end
node :created_at_time do |project_group|
project_group.created_at.to_formatted_s(:time)
end
node :can_edit_project do |project_group|
can?(:edit, @project)
end
child :project_requirements do
extends 'project_requirements/project_requirement'
end
jbuilder
json.content format_content(@message.content)
json.(@message, :created_at, :updated_at)
json.author do
json.name @message.creator.name.familiar
json.email_address @message.creator.email_address_with_name
json.url url_for(@message.creator, format: :json)
end
if current_user.admin?
json.visitors calculate_visitors(@message)
end
json.comments @message.comments, :content, :created_at
json.attachments @message.attachments do |attachment|
json.filename attachment.filename
json.url url_for(attachment)
end
ActiveModel::Serializers
Basic example
class Post < ActiveRecord::Base
end
class PostsController < ApplicationController
def show
render json: @post
end
end
class PostSerializer
attributes :id, :title, :body, :comments_count
has_many :comments
end
class CommentSerializer
end
Custom attributes
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id, :final_score, :name
def final_score
object.score.final
end
end
easy delegation for readablitity
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id, :total_questions_count
def total_questions_count
rfi_questions.size
end
delegate :rfi, to: :object
delegate :rfi_question, to: :rfi
end
Passing options
class Beta::RfiSolutionsController < ApplicationController
def show
render json: @rfi_solution, opportunity_rfi: @rfi_solution.opportunity_rfi
end
end
Serializing collection
class Beta::RfiSolutionsController < ApplicationController
def index
@presenter = RfiSolutionPresenter.new(@rfi, params)
render json: @presenter.rfi_solutions, each_serializer: RfxSolutionSerializer
end
end
has_many
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id
has_many :stakeholders # will use StakeholderSerializer and pass options
has_many :rfi_categories, serializer: RfiEvaluateRfiCategorySerializer
end
Custom collections
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id
has_many :stakeholders # will use StakeholderSerializer and pass options
def stakeholders
project.view_project_users.limit(6)
end
end
Caching
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id
delegate :cache_key, to: :object
end
Easy custom keys
class RfxSelectedSolutionSerializer < ActiveModel::Serializer
attributes :id
def cache_key
"#{user_cache_key}/#{rfi_cache_key}"
end
delegate :cache_key, to: :user, prefix: :true
delegate :cache_key, to: :rfi, prefix: true
end
Custom scope
class ApplicationController < ActionController::Base
serialization_scope :current_admin
end
A different user perhaps?
class CitiesController < ApplicationController
def show
@city = City.find(params[:id])
render json: @city, scope: User.most_important
end
end
And much much more!
Any questions?
ActiveModel::Serializers
By Bartek Kruszczyński
ActiveModel::Serializers
- 1,076