Reputation: 19969
I have used AMS (0.8) with Rails 3.2.19 but one place where I really struggle with them is how to control whether serializers include their associations or not. I obviously use AMS to build JSON Api's. Sometimes a serializer is the leaf or furthest out element and sometimes it's the top level and needs to include associations. My question is what is the best way to do this or is the solution I do below work (or is best solution).
I have seen some of the discussions but I find them very confusing (and version based). It's clear that for Serializer attributes or associations, there is an an include_XXX? method for each and you can return either a truthy or falsey statement here.
Here's my proposed code - it's a winemaker that has many wine_items. Is this how you would do this?
Model Classes:
class WineItem < ActiveRecord::Base
attr_accessible :name, :winemaker_id
belongs_to :winemaker
end
class Winemaker < ActiveRecord::Base
attr_accessible :name
has_many :wine_items
attr_accessor :show_items
end
Serializers:
class WinemakerSerializer < ActiveModel::Serializer
attributes :id, :name
has_many :wine_items
def include_wine_items?
object.show_items
end
end
class WineItemSerializer < ActiveModel::Serializer
attributes :id, :name
end
and in my controller:
class ApiWinemakersController < ApplicationController
def index
@winemakers=Winemaker.all
@winemakers.each { |wm| wm.show_items=true }
render json: @winemakers, each_serializer: WinemakerSerializer, root: "data"
end
end
Upvotes: 7
Views: 1951
Reputation: 4439
I ran into this issue myself and this is the cleanest solution so far (but I'm not a fan of it).
This method allows you to do things like:
/parents/1?include_children=true
or using a cleaner syntax like:
/parents/1?include=[children]
, etc...
# app/controllers/application_controller.rb
class ApplicationController
# Override scope for ActiveModel-Serializer (method defined below)
# See: https://github.com/rails-api/active_model_serializers/tree/0-8-stable#customizing-scope
serialization_scope(:serializer_scope)
private
# Whatever is in this method is accessible in the serializer classes.
# Pass in params for conditional includes.
def serializer_scope
OpenStruct.new(params: params, current_user: current_user)
end
end
# app/serializers/parent_serializer.rb
class ParentSerializer < ActiveModel::Serializer
has_many :children
def include_children?
params[:include_children] == true
# or if using other syntax:
# params[:includes].include?("children")
end
end
Kinda hackish to me, but it works. Hope you find it useful!
Upvotes: 1