module Flapjack::Gateways::JSONAPI::Methods::AssociationPatch
Public Class Methods
registered(app)
click to toggle source
# File lib/flapjack/gateways/jsonapi/methods/association_patch.rb, line 11 def self.registered(app) app.helpers Flapjack::Gateways::JSONAPI::Helpers::Headers app.helpers Flapjack::Gateways::JSONAPI::Helpers::Miscellaneous Flapjack::Gateways::JSONAPI::RESOURCE_CLASSES.each do |resource_class| resource = resource_class.short_model_name.plural jsonapi_links = if resource_class.respond_to?(:jsonapi_associations) resource_class.jsonapi_associations || {} else {} end singular_links = jsonapi_links.select {|n, jd| jd.link.is_a?(TrueClass) && jd.patch.is_a?(TrueClass) && :singular.eql?(jd.number) } multiple_links = jsonapi_links.select {|n, jd| jd.link.is_a?(TrueClass) && jd.patch.is_a?(TrueClass) && :multiple.eql?(jd.number) } unless singular_links.empty? && multiple_links.empty? app.class_eval do # GET and PATCH duplicate a lot of swagger code, but swagger-blocks # make it difficult to DRY things due to the different contexts in use single = resource.singularize singular_links.each_pair do |link_name, link_data| link_type = link_data.data_klass.short_model_name.name swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do operation :patch do key :description, link_data.descriptions[:patch] key :operationId, "replace_#{single}_#{link_name}" key :consumes, [JSONAPI_MEDIA_TYPE] parameter do key :name, "#{single}_id".to_sym key :in, :path key :description, "Id of a #{single}" key :required, true key :type, :string end parameter do key :name, :data key :in, :body key :description, "#{link_name} association to replace for the #{single}" key :required, true schema do key :"$ref", "#{link_type}Reference".to_sym end end response 204 do key :description, 'No Content; link update success' end response 403 do key :description, "Forbidden; no link id" schema do key :'$ref', :Errors end end response 404 do key :description, "Not Found" schema do key :'$ref', :Errors end end end end end multiple_links.each_pair do |link_name, link_data| link_type = link_data.data_klass.short_model_name.name swagger_path "/#{resource}/{#{single}_id}/relationships/#{link_name}" do operation :patch do key :description, link_data.descriptions[:patch] key :operationId, "replace_#{single}_#{link_name}" key :consumes, [JSONAPI_MEDIA_TYPE] parameter do key :name, "#{single}_id".to_sym key :in, :path key :description, "Id of a #{single}" key :required, true key :type, :string end parameter do key :name, :data key :in, :body key :description, "#{link_name} associations to replace for the #{single}" key :required, true schema do key :type, :array items do key :"$ref", "#{link_type}Reference".to_sym end end end response 204 do key :description, 'No Content; link update succeeded' end response 403 do key :description, "Forbidden; no link ids" schema do key :'$ref', :Errors end end response 404 do key :description, "Not Found" schema do key :'$ref', :Errors end end end end end end end id_patt = if Flapjack::Data::Tag.eql?(resource_class) "\\S+" else Flapjack::UUID_RE end assoc_patt = jsonapi_links.keys.map(&:to_s).join("|") app.patch %r{^/#{resource}/(#{id_patt})/relationships/(#{assoc_patt})$} do resource_id = params[:captures][0] assoc_name = params[:captures][1].to_sym halt(404) unless singular_links.has_key?(assoc_name) || multiple_links.has_key?(assoc_name) status 204 assoc = jsonapi_links[assoc_name] assoc_ids, _ = wrapped_link_params(:association => assoc, :allow_nil => true) resource_class.lock(*assoc.lock_klasses) do resource = resource_class.find_by_id!(resource_id) if :multiple.eql?(assoc.number) current_assoc_ids = resource.send(assoc_name).ids.to_a to_remove = current_assoc_ids - assoc_ids to_add = assoc_ids - current_assoc_ids resource.send(assoc_name).remove_ids(*to_remove) unless to_remove.empty? resource.send(assoc_name).add_ids(*to_add) unless to_add.empty? elsif :singular.eql?(assoc.number) if assoc_ids.nil? resource.send("#{assoc_name}=".to_sym, nil) else halt(err(403, "Trying to add multiple records to singular association '#{assoc_name}'")) if assoc_ids.size > 1 value = assoc_ids.first.nil? ? nil : assoc.data_klass.find_by_id!(assoc_ids.first) resource.send("#{assoc_name}=".to_sym, value) end end end end end end