class ViewModel::ActiveRecord::Cloner

def clone(node)

def clone(node)
  reset_state!
  new_model = node.model.dup
  pre_visit(node, new_model)
  return nil if ignored?
  if node.class.name
    class_name = node.class.name.underscore.gsub('/', '__')
    visit      = :"visit_#{class_name}"
    end_visit  = :"end_visit_#{class_name}"
  end
  if visit && respond_to?(visit, true)
    self.send(visit, node, new_model)
    return nil if ignored?
  end
  # visit the underlying viewmodel for each association, ignoring any
  # customization
  ignored_associations = @ignored_associations
  node.class._members.each do |name, association_data|
    next unless association_data.is_a?(ViewModel::ActiveRecord::AssociationData)
    reflection = association_data.direct_reflection
    if ignored_associations.include?(name)
      new_associated = association_data.collection? ? [] : nil
    else
      # Load the record associated with the old model
      associated = node.model.public_send(reflection.name)
      if associated.nil?
        new_associated = nil
      elsif !association_data.owned? && !association_data.through?
        # simply attach the associated target to the new model
        new_associated = associated
      else
        # Otherwise descend into the child, and attach the result
        build_vm = ->(model) do
          vm_class =
            if association_data.through?
              # descend into the synthetic join table viewmodel
              association_data.direct_viewmodel
            else
              association_data.viewmodel_class_for_model!(model.class)
            end
          vm_class.new(model)
        end
        new_associated =
          if ViewModel::Utils.array_like?(associated)
            associated.map { |m| clone(build_vm.(m)) }.compact
          else
            clone(build_vm.(associated))
          end
      end
    end
    new_association = new_model.association(reflection.name)
    new_association.writer(new_associated)
  end
  if end_visit && respond_to?(end_visit, true)
    self.send(end_visit, node, new_model)
  end
  post_visit(node, new_model)
  new_model
end