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