metamaps--metamaps/app/serializers/api/v2/application_serializer.rb
Devin Howard e544d6a6db refactor api and fix bugs (#1088)
* fix weird double-embed issue

* fix users/current api if not logged in

* turbocharge the api

* fix docs
2017-03-09 14:24:52 -05:00

65 lines
2.7 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
# Here's an example object that could be passed in self.embeddable: {
# creator: {
# serializer: UserSerializer,
# },
# collaborators: {
# serializer: UserSerializer
# },
# topic: {},
# synapses: {}
# }
# The key has to be in embeddable or it won't show in the response, and the serializer is
# only needed if the key doesn't match a serializer
def self.embed_dat
embeddable.each_pair do |key, opts|
is_plural = key.to_s.pluralize == key.to_s
id_key = key.to_s.singularize + (is_plural ? '_ids' : '_id')
serializer = opts.delete(:serializer) || "Api::V2::#{key.to_s.singularize.camelize}Serializer".constantize
if is_plural
attribute(id_key.to_sym, opts.merge(unless: -> { embeds.include?(key) })) do
Pundit.policy_scope(scope[:current_user], object.send(key))&.map(&:id) || []
end
has_many(key, opts.merge(if: -> { embeds.include?(key) })) do
list = Pundit.policy_scope(scope[:current_user], object.send(key)) || []
resource = ActiveModelSerializers::SerializableResource.new(
list,
each_serializer: serializer,
scope: scope.merge(embeds: [])
)
# resource.as_json will return e.g. { users: [ ... ] } for collaborators
# since we can't get the :users key, convert to an array and use .first.second to get the needed values
resource&.as_json&.to_a&.first&.second
end
else
attribute(id_key.to_sym, opts.merge(unless: -> { embeds.include?(key) }))
attribute(key, opts.merge(if: -> { embeds.include?(key) })) do |parent_serializer|
object = parent_serializer.object.send(key)
next nil if object.nil?
resource = ActiveModelSerializers::SerializableResource.new(
object,
serializer: serializer,
scope: scope.merge(embeds: [])
)
resource&.as_json&.to_a&.first&.second
end
end
end
end
end
end
end