module ActiveFedora::NestedAttributes

def _destroy

See ActionView::Helpers::FormHelper::fields_for for more info.

destruction of this association.
used in conjunction with fields_for to build a form element for the
Returns ActiveFedora::Base#marked_for_destruction? It's
def _destroy
  marked_for_destruction?
end

def assign_nested_attributes_for_collection_association(association_name, attributes_collection)

def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
  options = nested_attributes_options[association_name]
  if options[:limit] && attributes_collection.size > options[:limit]
    raise TooManyRecords, "Maximum #{options[:limit]} records are allowed. Got #{attributes_collection.size} records instead."
  end
  if attributes_collection.is_a? Hash
    keys = attributes_collection.keys
    attributes_collection = if keys.include?('id') || keys.include?(:id)
      Array(attributes_collection)
    else
      attributes_collection.sort_by { |i, _| i.to_i }.map { |_, attributes| attributes }
    end
  end
  association = send(association_name)
  existing_records = if association.loaded?
    association.to_a
  else
    attribute_ids = attributes_collection.map {|a| a['id'] || a[:id] }.compact
    attribute_ids.present? ? association.to_a.select{ |x| attribute_ids.include?(x.id)} : []
  end
  attributes_collection.each do |attributes|
    attributes = attributes.with_indifferent_access
    if attributes['id'].blank?
      association.build(attributes.except(*UNASSIGNABLE_KEYS)) unless call_reject_if(association_name, attributes)
    elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
      association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && !call_reject_if(association_name, attributes)
      if !call_reject_if(association_name, attributes)
        assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
      end
    else
      raise_nested_attributes_record_not_found(association_name, attributes['id'])
    end
  end
end

def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)

+allow_destroy+ is +true+ and has_destroy_flag? returns +true+.
Updates a record with the +attributes+ or marks it for destruction if
def assign_to_or_mark_for_destruction(record, attributes, allow_destroy)
  record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
  record.mark_for_destruction if has_destroy_flag?(attributes) && allow_destroy
end

def call_reject_if(association_name, attributes)

def call_reject_if(association_name, attributes)
  return false if has_destroy_flag?(attributes)
  case callback = self.nested_attributes_options[association_name][:reject_if]
  when Symbol
    method(callback).arity == 0 ? send(callback) : send(callback, attributes)
  when Proc
    callback.call(attributes)
  end
end

def has_destroy_flag?(hash)

Determines if a hash contains a truthy _destroy key.
def has_destroy_flag?(hash)
  ["1", "true"].include?(hash['_destroy'].to_s)
end

def raise_nested_attributes_record_not_found(association_name, record_id)

def raise_nested_attributes_record_not_found(association_name, record_id)
  reflection = self.class.reflect_on_association(association_name)
  raise ObjectNotFoundError, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
end