Search code examples
ruby-on-railsserializationpolymorphismactive-model-serializerspg-search

Rails AMS, specify different serializers in polymorphic list


I implemented a multi-table search using pg_search, and then serialize the result with Active Model Serializer (version 0.10) - it works fine, but AMS uses the default serializer for each of the types returned.

Here's the serializer:

class SearchBarSerializer < ApplicationSerializer
  attributes :searchable_type
  belongs_to :searchable
end

Thus, for example, when serializing the returned objects from pg_search, if the relevant object is a "User", then AMS uses UserSerializer. If the relevant type is a league, then AMS uses LeagueSerializer.

That's fine - but I would like to use a different serializer for each type. This is for a search bar, and so I only care about a much smaller amount of data than the full standard serializer. (EDIT: the standard serializers serialize all attributes and associations for each of the User and League models, which can be seen below. Each model is somewhat significantly large, and for the purposes of just a search, I really only need each model's name and id, and perhaps some other smaller data for each type)

Is there some way that I can specify which serializer to use depending on the object?

Thank you!

EDIT:

User Model:

class User < ActiveRecord::Base
  include PgSearch

  #################### Associations
  has_and_belongs_to_many :roles
  belongs_to :profile_page_visibility, optional: true # the optional part is just for when user's are created.
  has_and_belongs_to_many :leagues, class_name: "Leagues::League", join_table: "users_leagues_leagues"
  has_one :customer, class_name: "Payments::Customer", dependent: :destroy
  has_many :unpaid_charges, class_name: "Payments::UnpaidCharge", dependent: :destroy
  has_many :charges, class_name: "Payments::Charge", dependent: :destroy
  has_many :cards, class_name: "Payments::Card", dependent: :destroy
  has_many :league_join_requests, class_name: "Leagues::JoinRequest", dependent: :destroy
  has_many :notifications, class_name: "Notification", foreign_key: :recipient_id
  has_many :league_invitations, class_name: "Leagues::Invitation", dependent: :destroy
  has_many :teams, class_name: "Leagues::Team"
  has_many :divisions, class_name: "Leagues::Division" # Can act as division commissioner
  has_many :conferences, class_name: "Leagues::Conference" # Can act as conference commissioner

League Model:

class Leagues::League < ApplicationRecord
  enum pay_level: [ :basic, :custom, :premium ]
  include PgSearch

  #################### Associations
  has_and_belongs_to_many :users, class_name: "User", join_table: "users_leagues_leagues"
  has_and_belongs_to_many :commissioners, class_name: "User", join_table: "commissioners_leagues_leagues"
  belongs_to :commissioner, class_name: "User", foreign_key: :commissioner_id, optional: true
  has_and_belongs_to_many :feature_requests, class_name: "FeatureRequest", join_table: "feature_requests_leagues_leagues"
  has_many :join_requests, class_name: "Leagues::JoinRequest", dependent: :destroy
  has_many :invitations, class_name: "Leagues::Invitation", dependent: :destroy
  has_many :notifications, class_name: "Notification", as: :notifiable_subject, dependent: :destroy
  has_many :teams, class_name: "Leagues::Team", dependent: :destroy
  has_many :conferences, class_name: "Leagues::Conference", dependent: :destroy
  has_many :divisions, class_name: "Leagues::Division", dependent: :destroy

Solution

  • If you want to define a specific serializer lookup for your associations, you can override the ActiveModel::Serializer.serializer_for method to return a serializer class based on defined conditions.

    For your case, it might look something like:

    class SearchBarSerializer < ApplicationSerializer
      attributes :searchable_type
      belongs_to :searchable
    
      class << self
        def serializer_for(model, options)
          return TinyUserSerializer if model.class == User
          return TinyLeagueSerializer if model.class == Leagues::League
    
          super
        end
      end
    end