refactor api and fix bugs (#1088)

* fix weird double-embed issue

* fix users/current api if not logged in

* turbocharge the api

* fix docs
This commit is contained in:
Devin Howard 2017-03-09 11:24:52 -08:00 committed by Connor Turland
parent 780e66632b
commit e544d6a6db
4 changed files with 33 additions and 33 deletions

View file

@ -3,6 +3,7 @@ module Api
module V2 module V2
class UsersController < RestfulController class UsersController < RestfulController
def current def current
raise Pundit::NotAuthorizedError if current_user.nil?
@user = current_user @user = current_user
authorize @user authorize @user
show # delegate to the normal show function show # delegate to the normal show function

View file

@ -13,50 +13,49 @@ module Api
@embeds ||= (scope[:embeds] || []).select { |e| self.class.embeddable.keys.include?(e) } @embeds ||= (scope[:embeds] || []).select { |e| self.class.embeddable.keys.include?(e) }
end end
# self.embeddable might look like this: # Here's an example object that could be passed in self.embeddable: {
# creator: { attr: :first_creator, serializer: UserSerializer } # creator: {
# contributors: { serializer: UserSerializer} # 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 # collaborators: {
# in the hash will be passed to the ActiveModel::Serializer `attribute` method # serializer: UserSerializer
# directly (e.g. serializer in the examples will be passed). # },
# # topic: {},
# This setup means if you passed this self.embeddable config and sent no # synapses: {}
# ?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 # The key has to be in embeddable or it won't show in the response, and the serializer is
# then instead of an id and an array of ids, you would get a serialized user # only needed if the key doesn't match a serializer
# (the first_creator) and an array of serialized users (the contributors).
def self.embed_dat def self.embed_dat
embeddable.each_pair do |key, opts| embeddable.each_pair do |key, opts|
attr = opts.delete(:attr) || key is_plural = key.to_s.pluralize == key.to_s
if attr.to_s.pluralize == attr.to_s id_key = key.to_s.singularize + (is_plural ? '_ids' : '_id')
attribute("#{attr.to_s.singularize}_ids".to_sym, serializer = opts.delete(:serializer) || "Api::V2::#{key.to_s.singularize.camelize}Serializer".constantize
opts.merge(unless: -> { embeds.include?(key) })) do if is_plural
Pundit.policy_scope(scope[:current_user], object.send(attr))&.map(&:id) || [] attribute(id_key.to_sym, opts.merge(unless: -> { embeds.include?(key) })) do
Pundit.policy_scope(scope[:current_user], object.send(key))&.map(&:id) || []
end end
has_many(attr, opts.merge(if: -> { embeds.include?(key) })) do has_many(key, opts.merge(if: -> { embeds.include?(key) })) do
list = Pundit.policy_scope(scope[:current_user], object.send(attr)) || [] list = Pundit.policy_scope(scope[:current_user], object.send(key)) || []
child_serializer = "Api::V2::#{attr.to_s.singularize.camelize}Serializer".constantize
resource = ActiveModelSerializers::SerializableResource.new( resource = ActiveModelSerializers::SerializableResource.new(
list, list,
each_serializer: child_serializer, each_serializer: serializer,
scope: scope.merge(embeds: []) scope: scope.merge(embeds: [])
) )
resource.as_json # 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 end
else else
id_opts = opts.merge(key: "#{key}_id") attribute(id_key.to_sym, opts.merge(unless: -> { embeds.include?(key) }))
attribute("#{attr}_id".to_sym, attribute(key, opts.merge(if: -> { embeds.include?(key) })) do |parent_serializer|
id_opts.merge(unless: -> { embeds.include?(key) })) object = parent_serializer.object.send(key)
attribute(key, opts.merge(if: -> { embeds.include?(key) })) do |serializer| next nil if object.nil?
object = serializer.object.send(key)
child_serializer = "Api::V2::#{object.class.name}Serializer".constantize
resource = ActiveModelSerializers::SerializableResource.new( resource = ActiveModelSerializers::SerializableResource.new(
object, object,
serializer: child_serializer, serializer: serializer,
scope: scope.merge(embeds: []) scope: scope.merge(embeds: [])
) )
resource.as_json resource&.as_json&.to_a&.first&.second
end end
end end
end end

View file

@ -18,7 +18,7 @@ module Api
def self.embeddable def self.embeddable
{ {
user: {}, user: {},
source: {}, source: { serializer: MapSerializer },
topics: {}, topics: {},
synapses: {}, synapses: {},
mappings: {}, mappings: {},

View file

@ -14,7 +14,7 @@ module Api
def self.embeddable def self.embeddable
{ {
user: {}, user: {},
updated_by: {}, updated_by: { serializer: UserSerializer },
map: {} map: {}
} }
end end