Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to conditionally include associations in a Rails Active Model Serializer v0.8

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
like image 929
timpone Avatar asked Dec 02 '14 01:12

timpone


1 Answers

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!

like image 127
Dan L Avatar answered Oct 18 '22 02:10

Dan L