Search code examples
ruby-on-rails-3ruby-on-rails-3.2active-model-serializers

Load associations to one level while conditionally sideloading associations in Active model serializers


AMS version 0.8.3,

I created a base_serializer.rb like this and extended the same.

class BaseSerializer < ActiveModel::Serializer
  def include_associations!
    if @options[:embed]
      embed = @options[:embed].split(',').map{|item| item.strip.to_sym}
      embed.each do |assoc|
        include! assoc if _associations.keys.include?(assoc)
      end
    end
  end
end

class EventSerializer < BaseSerializer
  attributes :id, :name
  has_many :organizers, serializer: OrganizerSerializer
  has_many :participants, serializer: ParticipantSerializer
end

class OrganizerSerializer < BaseSerializer
  attributes :id, :name
  has_many :related, serializer: RelatedSerializer
end

class ParticipantSerializer < BaseSerializer
  attributes :id, :name
  has_many :related, serializer: RelatedSerializer
end

class RelatedSerializer < BaseSerializer
  attributes :id, :name
  has_many :something, serializer: SomethingSerializer
end

and the index method in EventsController is written as

# GET /events?embed=organizers,participants
  def index
      @events = Event.all
      render json: @events, embed: params[:embed]
  end

With this I can get the :id and :name of events, organizers and participants. But, I want the attributes of related association as well. I don't need details of something serializer. I want to go till this level for each association. How can I achieve that?


Solution

  • I ended up doing this to achieve the same.

    class BaseSerializer < ActiveModel::Serializer
      def include_associations!
        @options[:embed_level] ||= 2
        return unless @options.key?(:embed) && @options[:embed_level] != 0
        embed = @options[:embed].split(',').map{|item| item.strip.to_sym}
        embed.each do |assoc|
          next unless _associations.key?(assoc)
          assoc_serializer = serializer_for(assoc)
          embed = @options[:embed]
          embed_level = @options[:embed_level]
          @options[:embed_level] = @options[:embed_level] - 1
          @options[:embed] = assoc_serializer._associations.keys.join(",")
          include! assoc
          @options[:embed_level] = embed_level
        end
      end
    
      def serializer_for(assoc)
        serializer = _associations[assoc].options[:serializer]
        return serializer if serializer
        assoc.to_s.classify.concat("Serializer").constantize
      end
    end
    

    Ref: Github Issue Link Special Thanks to Yohan Robert!!!