metamaps--metamaps/app/serializers/api/v2/application_serializer.rb
Devin Howard a9f19815e4 fix api embed to use the correct serializers (fix #998) (#1029)
* use correct serializer for singular embeds in api (almost fixes #998)

* fix has_many api embeds too!

* unused arg
2017-01-19 14:49:40 -05:00

66 lines
3 KiB
Ruby

# frozen_string_literal: true
module Api
module V2
class ApplicationSerializer < ActiveModel::Serializer
def self.embeddable
{}
end
def embeds
# subclasses can override self.embeddable, and then it will whitelist
# scope[:embeds] based on the contents. That way scope[:embeds] can just pull
# from params and the whitelisting happens here
@embeds ||= (scope[:embeds] || []).select { |e| self.class.embeddable.keys.include?(e) }
end
# self.embeddable might look like this:
# creator: { attr: :first_creator, serializer: UserSerializer }
# contributors: { serializer: UserSerializer}
# This method will remove the :attr key if the underlying attribute name
# is different than the name provided in the final json output. All other keys
# in the hash will be passed to the ActiveModel::Serializer `attribute` method
# directly (e.g. serializer in the examples will be passed).
#
# This setup means if you passed this self.embeddable config and sent no
# ?embed= query param with your API request, you would get the regular attributes
# plus creator_id and contributor_ids. If you passed ?embed=creator,contributors
# then instead of an id and an array of ids, you would get a serialized user
# (the first_creator) and an array of serialized users (the contributors).
def self.embed_dat
embeddable.each_pair do |key, opts|
attr = opts.delete(:attr) || key
if attr.to_s.pluralize == attr.to_s
attribute("#{attr.to_s.singularize}_ids".to_sym,
opts.merge(unless: -> { embeds.include?(key) })) do
Pundit.policy_scope(scope[:current_user], object.send(attr))&.map(&:id) || []
end
has_many(attr, opts.merge(if: -> { embeds.include?(key) })) do
list = Pundit.policy_scope(scope[:current_user], object.send(attr)) || []
child_serializer = "Api::V2::#{attr.to_s.singularize.camelize}Serializer".constantize
resource = ActiveModelSerializers::SerializableResource.new(
list,
each_serializer: child_serializer,
scope: scope.merge(embeds: [])
)
resource.as_json
end
else
id_opts = opts.merge(key: "#{key}_id")
attribute("#{attr}_id".to_sym,
id_opts.merge(unless: -> { embeds.include?(key) }))
attribute(key, opts.merge(if: -> { embeds.include?(key) })) do |serializer|
object = serializer.object.send(key)
child_serializer = "Api::V2::#{object.class.name}Serializer".constantize
resource = ActiveModelSerializers::SerializableResource.new(
object,
serializer: child_serializer,
scope: scope.merge(embeds: [])
)
resource.as_json
end
end
end
end
end
end
end