# frozen_string_literal: truerequire'view_model/active_record/nested_controller_base'# Controller mixin for accessing a root ViewModel which can be accessed in a# collection by a parent model.# Contributes the following routes:# PUT /parents/:parent_id/children #append -- deserialize (possibly existing) children and append to collection# POST /parents/:parent_id/children #replace -- deserialize (possibly existing) children, replacing existing collection# GET /parents/:parent_id/children #index_associated -- list collection# DELETE /parents/:parent_id/children/:child_id #disassociate -- delete relationship between parent/child (possibly garbage-collecting child)# DELETE /parents/:parent_id/children #disassociate_all -- delete relationship from parent to all children## Inherits the following routes to manipulate children directly:# POST /children #create -- create or update without parent# GET /children #index -- list all child models regardless of parent# GET /children/:id #show# DELETE /children/:id #destroymoduleViewModel::ActiveRecord::CollectionNestedControllerextendActiveSupport::ConcernincludeViewModel::ActiveRecord::NestedControllerBasedefindex_associated(scope: nil,serialize_context: new_serialize_context,lock_owner: nil,&block)show_association(scope: scope,serialize_context: serialize_context,lock_owner: lock_owner,&block)end# Deserialize items of the associated type and associate them with the owner,# replacing previously associated items.defreplace(serialize_context: new_serialize_context,deserialize_context: new_deserialize_context,lock_owner: nil,&block)write_association(serialize_context: serialize_context,deserialize_context: deserialize_context,lock_owner: lock_owner,&block)enddefreplace_bulk(serialize_context: new_serialize_context,deserialize_context: new_deserialize_context,&block)write_association_bulk(serialize_context: serialize_context,deserialize_context: deserialize_context,&block)enddefdisassociate_all(serialize_context: new_serialize_context,deserialize_context: new_deserialize_context,lock_owner: nil)destroy_association(true,serialize_context: serialize_context,deserialize_context: deserialize_context,lock_owner: lock_owner)end# Deserialize items of the associated type and append them to the owner's# collection.defappend(serialize_context: new_serialize_context,deserialize_context: new_deserialize_context,lock_owner: nil)assoc_view=nilpre_rendered=owner_viewmodel.transactiondoupdate_hash,refs=parse_viewmodel_updatesbefore=parse_relative_position(:before)after=parse_relative_position(:after)ifbefore&&afterraiseViewModel::DeserializationError::InvalidSyntax.new('Can not provide both `before` and `after` anchors for a collection append')endowner_view=owner_viewmodel.find(owner_viewmodel_id,eager_include: false,lock: lock_owner)assoc_view=owner_view.append_associated(association_name,update_hash,references: refs,before: before,after: after,deserialize_context: deserialize_context)ViewModel::Callbacks.wrap_serialize(owner_view,context: serialize_context)dochild_context=owner_view.context_for_child(association_name,context: serialize_context)ViewModel.preload_for_serialization(assoc_view)assoc_view=yield(assoc_view)ifblock_given?prerender_viewmodel(assoc_view,serialize_context: child_context)endendrender_json_string(pre_rendered)assoc_viewenddefdisassociate(serialize_context: new_serialize_context,deserialize_context: new_deserialize_context,lock_owner: nil)owner_viewmodel.transactiondoowner_view=owner_viewmodel.find(owner_viewmodel_id,eager_include: false,lock: lock_owner)owner_view.delete_associated(association_name,viewmodel_id,type: viewmodel_class,deserialize_context: deserialize_context)render_viewmodel(nil)endendprivatedefparse_relative_position(name)id=parse_uuid_param(name,default: nil)ifidifassociation_data.polymorphic?type_name=parse_param("#{name}_type")type=association_data.viewmodel_class_for_name(type_name)iftype.nil?raiseViewModel::DeserializationError::InvalidAssociationType.new(association_data.association_name.to_s,type_name)endelsetype=owner_viewmodel.viewmodel_classendViewModel::Reference.new(type,id)elsenilendendend