module ViewModel::ActiveRecord::AssociationManipulation

def replace_associated(association_name, update_hash, references: {}, deserialize_context: self.class.new_deserialize_context)

Replace the current member(s) of an association with the provided hash(es).
def replace_associated(association_name, update_hash, references: {}, deserialize_context: self.class.new_deserialize_context)
  association_data = self.class._association_data(association_name)
  # TODO: structure checking
  if association_data.through? || association_data.shared?
    is_fupdate =
      association_data.collection? &&
      update_hash.is_a?(Hash) &&
      update_hash[ViewModel::ActiveRecord::TYPE_ATTRIBUTE] == ViewModel::ActiveRecord::FUNCTIONAL_UPDATE_TYPE
    if is_fupdate
      update_hash[ViewModel::ActiveRecord::ACTIONS_ATTRIBUTE].each_with_index do |action, i|
        action_type_name = action[ViewModel::ActiveRecord::TYPE_ATTRIBUTE]
        if action_type_name == ViewModel::ActiveRecord::FunctionalUpdate::Remove::NAME
          # Remove actions are always type/id refs; others need to be translated to proper refs
          next
        end
        association_references = convert_updates_to_references(
          action[ViewModel::ActiveRecord::VALUES_ATTRIBUTE],
          key: "#{action_type_name}_#{i}")
        references.merge!(association_references)
        action[ViewModel::ActiveRecord::VALUES_ATTRIBUTE] =
          association_references.each_key.map { |ref| { ViewModel::REFERENCE_ATTRIBUTE => ref } }
      end
    else
      update_hash = ViewModel::Utils.wrap_one_or_many(update_hash) do |sh|
        association_references = convert_updates_to_references(sh, key: 'replace')
        references.merge!(association_references)
        association_references.each_key.map { |ref| { ViewModel::REFERENCE_ATTRIBUTE => ref } }
      end
    end
  end
  root_update_hash = {
    ViewModel::ID_ATTRIBUTE   => self.id,
    ViewModel::TYPE_ATTRIBUTE => self.class.view_name,
    association_name.to_s     => update_hash,
  }
  root_update_viewmodel = self.class.deserialize_from_view(root_update_hash, references: references, deserialize_context: deserialize_context)
  root_update_viewmodel._read_association(association_name)
end