lib/jsonapi_compliable/util/persistence.rb in jsonapi_compliable-0.7.9 vs lib/jsonapi_compliable/util/persistence.rb in jsonapi_compliable-0.8.0

- old
+ new

@@ -3,15 +3,16 @@ class JsonapiCompliable::Util::Persistence # @param [Resource] resource the resource instance # @param [Hash] meta see (Deserializer#meta) # @param [Hash] attributes see (Deserializer#attributes) # @param [Hash] relationships see (Deserializer#relationships) - def initialize(resource, meta, attributes, relationships) + def initialize(resource, meta, attributes, relationships, caller_model) @resource = resource @meta = meta @attributes = attributes @relationships = relationships + @caller_model = caller_model end # Perform the actual save logic. # # belongs_to must be processed before/separately from has_many - @@ -35,11 +36,11 @@ persisted = persist_object(@meta[:method], @attributes) assign_temp_id(persisted, @meta[:temp_id]) associate_parents(persisted, parents) - children = process_has_many(@relationships) do |x| + children = process_has_many(@relationships, persisted) do |x| update_foreign_key(persisted, x[:attributes], x) end associate_children(persisted, children) persisted unless @meta[:method] == :destroy @@ -47,11 +48,15 @@ private # The child's attributes should be modified to nil-out the # foreign_key when the parent is being destroyed or disassociated + # + # This is not the case for HABTM, whose "foreign key" is a join table def update_foreign_key(parent_object, attrs, x) + return if x[:sideload].type == :habtm + if [:destroy, :disassociate].include?(x[:meta][:method]) attrs[x[:foreign_key]] = nil update_foreign_type(attrs, x, null: true) if x[:is_polymorphic] else attrs[x[:foreign_key]] = parent_object.send(x[:primary_key]) @@ -70,37 +75,49 @@ end end def associate_parents(object, parents) parents.each do |x| - x[:sideload].associate(x[:object], object) if x[:object] && object + if x[:object] && object + if x[:meta][:method] == :disassociate + x[:sideload].disassociate(x[:object], object) + else + x[:sideload].associate(x[:object], object) + end + end end end def associate_children(object, children) children.each do |x| - x[:sideload].associate(object, x[:object]) if x[:object] && object + if x[:object] && object + if x[:meta][:method] == :disassociate + x[:sideload].disassociate(object, x[:object]) + else + x[:sideload].associate(object, x[:object]) + end + end end end def persist_object(method, attributes) case method when :destroy - @resource.destroy(attributes[:id]) - when :disassociate, nil - @resource.update(attributes) + call_resource_method(:destroy, attributes[:id], @caller_model) + when :update, nil, :disassociate + call_resource_method(:update, attributes, @caller_model) else - @resource.send(method, attributes) + call_resource_method(:create, attributes, @caller_model) end end - def process_has_many(relationships) + def process_has_many(relationships, caller_model) [].tap do |processed| iterate(except: [:polymorphic_belongs_to, :belongs_to]) do |x| yield x x[:object] = x[:sideload].resource - .persist_with_relationships(x[:meta], x[:attributes], x[:relationships]) + .persist_with_relationships(x[:meta], x[:attributes], x[:relationships], caller_model) processed << x end end end @@ -124,8 +141,27 @@ relationships: @relationships, }.merge(only: only, except: except) JsonapiCompliable::Util::RelationshipPayload.iterate(opts) do |x| yield x + end + end + + # In the Resource, we want to allow: + # + # def create(attrs) + # + # and + # + # def create(attrs, parent = nil) + # + # 'parent' is an optional parameter that should not be part of the + # method signature in most use cases. + def call_resource_method(method_name, attributes, caller_model) + method = @resource.method(method_name) + if [2,-2].include?(method.arity) + method.call(attributes, caller_model) + else + method.call(attributes) end end end