module ActiveRecord::NestedAttributes

def self.included(base)

def self.included(base)
  base.extend(ClassMethods)
  base.class_inheritable_accessor :nested_attributes_options, :instance_writer => false
  base.nested_attributes_options = {}
end

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 ActiveRecord::AutosaveAssociation::marked_for_destruction? It's
def _destroy
  marked_for_destruction?
end

def assign_nested_attributes_for_collection_association(association_name, attributes_collection)

])
{ :id => '2', :_destroy => true }
{ :name => 'John' },
{ :id => '1', :name => 'Peter' },
assign_nested_attributes_for_collection_association(:people, [

Also accepts an Array of attribute hashes:

for destruction.
person with the name `John', and mark the associatied Person with ID 2
Will update the name of the Person with ID 1, build a new associated

})
'3' => { :id => '2', :_destroy => true }
'2' => { :name => 'John' },
'1' => { :id => '1', :name => 'Peter' },
assign_nested_attributes_for_collection_association(:people, {

For example:

matched record for destruction.
value and a :_destroy key set to a truthy value will mark the
a new record for the association. Hashes with a matching :id
will update that record. Hashes without an :id value will build
Hashes with an :id value matching an existing associated record

Assigns the given attributes to the collection association.
def assign_nested_attributes_for_collection_association(association_name, attributes_collection)
  options = nested_attributes_options[association_name]
  unless attributes_collection.is_a?(Hash) || attributes_collection.is_a?(Array)
    raise ArgumentError, "Hash or Array expected, got #{attributes_collection.class.name} (#{attributes_collection.inspect})"
  end
  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
    attributes_collection = attributes_collection.sort_by { |index, _| index.to_i }.map { |_, attributes| attributes }
  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.all(:conditions => {association.primary_key => attribute_ids}) : []
  end
  attributes_collection.each do |attributes|
    attributes = attributes.with_indifferent_access
    if attributes['id'].blank?
      unless reject_new_record?(association_name, attributes)
        association.build(attributes.except(*UNASSIGNABLE_KEYS))
      end
    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) unless association.loaded?
      assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
    else
      raise_nested_attributes_record_not_found(association_name, attributes['id'])
    end
  end
end

def assign_nested_attributes_for_one_to_one_association(association_name, attributes)

then the existing record will be marked for destruction.
update_only is true, and a :_destroy key set to a truthy value,
If the given attributes include a matching :id attribute, or

object exists. Otherwise a new record will be built.
modified. If update_only is true, a new record is only created when no
that matches the existing record’s id, then the existing record will be
If update_only is false and the given attributes include an :id

Assigns the given attributes to the association.
def assign_nested_attributes_for_one_to_one_association(association_name, attributes)
  options = nested_attributes_options[association_name]
  attributes = attributes.with_indifferent_access
  check_existing_record = (options[:update_only] || !attributes['id'].blank?)
  if check_existing_record && (record = send(association_name)) &&
      (options[:update_only] || record.id.to_s == attributes['id'].to_s)
    assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy])
  elsif attributes['id']
    raise_nested_attributes_record_not_found(association_name, attributes['id'])
  elsif !reject_new_record?(association_name, attributes)
    method = "build_#{association_name}"
    if respond_to?(method)
      send(method, attributes.except(*UNASSIGNABLE_KEYS))
    else
      raise ArgumentError, "Cannot build association #{association_name}. Are you trying to build a polymorphic one-to-one association?"
    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)
  if has_destroy_flag?(attributes) && allow_destroy
    record.mark_for_destruction
  else
    record.attributes = attributes.except(*UNASSIGNABLE_KEYS)
  end
end

def call_reject_if(association_name, attributes)

def call_reject_if(association_name, attributes)
  case callback = 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)
  ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
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 RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
end

def reject_new_record?(association_name, attributes)

association and evaluates to +true+.
has_destroy_flag? or if a :reject_if proc exists for this
Determines if a new record should be build by checking for
def reject_new_record?(association_name, attributes)
  has_destroy_flag?(attributes) || call_reject_if(association_name, attributes)
end