module ActiveRecord::AutosaveAssociation

def _ensure_no_duplicate_errors

def _ensure_no_duplicate_errors
  errors.uniq!
end

def _record_changed?(reflection, record, key)

If the record is new or it has changed, returns true.
def _record_changed?(reflection, record, key)
  record.new_record? ||
    association_foreign_key_changed?(reflection, record, key) ||
    record.will_save_change_to_attribute?(reflection.foreign_key)
end

def around_save_collection_association

association whether or not the parent was a new record before saving.
Is used as an around_save callback to check while saving a collection
def around_save_collection_association
  previously_new_record_before_save = (@new_record_before_save ||= false)
  @new_record_before_save = !previously_new_record_before_save && new_record?
  yield
ensure
  @new_record_before_save = previously_new_record_before_save
end

def associated_records_to_validate_or_save(association, new_record, autosave)

unless the parent is/was a new record itself.
or saved. If +autosave+ is +false+ only new records will be returned,
Returns the record for an association collection that should be validated
def associated_records_to_validate_or_save(association, new_record, autosave)
  if new_record || custom_validation_context?
    association && association.target
  elsif autosave
    association.target.find_all(&:changed_for_autosave?)
  else
    association.target.find_all(&:new_record?)
  end
end

def association_foreign_key_changed?(reflection, record, key)

def association_foreign_key_changed?(reflection, record, key)
  return false if reflection.through_reflection?
  record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key
end

def association_valid?(reflection, record, index = nil)

enabled records if they're marked_for_destruction? or destroyed.
the parent, self, if it wasn't. Skips any :autosave
Returns whether or not the association is valid and applies any errors to
def association_valid?(reflection, record, index = nil)
  return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
  context = validation_context if custom_validation_context?
  unless valid = record.valid?(context)
    if reflection.options[:autosave]
      indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord.index_nested_attribute_errors)
      record.errors.group_by_attribute.each { |attribute, errors|
        attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
        errors.each { |error|
          self.errors.import(
            error,
            attribute: attribute
          )
        }
      }
    else
      errors.add(reflection.name)
    end
  end
  valid
end

def changed_for_autosave?

any of its nested autosave associations are likewise changed)
Returns whether or not this record has been changed in any way (including whether
def changed_for_autosave?
  new_record? || has_changes_to_save? || marked_for_destruction? || nested_records_changed_for_autosave?
end

def custom_validation_context?

def custom_validation_context?
  validation_context && [:create, :update].exclude?(validation_context)
end

def destroyed_by_association

Used to avoid updating the counter cache unnecessarily.

Returns the association for the parent being destroyed.
def destroyed_by_association
  @destroyed_by_association
end

def destroyed_by_association=(reflection)

record in the process.
Records the association that is being destroyed and destroying this
def destroyed_by_association=(reflection)
  @destroyed_by_association = reflection
end

def mark_for_destruction

Only useful if the :autosave option on the parent is enabled for this associated model.

when parent.save is called.
This does _not_ actually destroy the record instantly, rather child record will be destroyed
Marks this record to be destroyed as part of the parent's save transaction.
def mark_for_destruction
  @marked_for_destruction = true
end

def marked_for_destruction?

Only useful if the :autosave option on the parent is enabled for this associated model.

Returns whether or not this record will be destroyed as part of the parent's save transaction.
def marked_for_destruction?
  @marked_for_destruction
end

def nested_records_changed_for_autosave?

Returns false if already called to prevent an infinite loop.
any new ones), and return true if any are changed for autosave.
Go through nested autosave associations that are loaded in memory (without loading
def nested_records_changed_for_autosave?
  @_nested_records_changed_for_autosave_already_called ||= false
  return false if @_nested_records_changed_for_autosave_already_called
  begin
    @_nested_records_changed_for_autosave_already_called = true
    self.class._reflections.values.any? do |reflection|
      if reflection.options[:autosave]
        association = association_instance_get(reflection.name)
        association && Array.wrap(association.target).any?(&:changed_for_autosave?)
      end
    end
  ensure
    @_nested_records_changed_for_autosave_already_called = false
  end
end

def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)

def normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
  normalized_attribute =
    if indexed_attribute
      "#{reflection.name}[#{index}]"
    else
      reflection.name
    end
  normalized_attribute = "#{normalized_attribute}.#{attribute}" if attribute != :base
  normalized_attribute
end

def reload(options = nil)

Reloads the attributes of the object as usual and clears marked_for_destruction flag.
def reload(options = nil)
  @marked_for_destruction = false
  @destroyed_by_association = nil
  super
end

def save_belongs_to_association(reflection)

In addition, it will destroy the association if it was marked for destruction.

Saves the associated record if it's new or :autosave is enabled.
def save_belongs_to_association(reflection)
  association = association_instance_get(reflection.name)
  return unless association && association.loaded? && !association.stale_target?
  record = association.load_target
  if record && !record.destroyed?
    autosave = reflection.options[:autosave]
    if autosave && record.marked_for_destruction?
      self[reflection.foreign_key] = nil
      record.destroy
    elsif autosave != false
      saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
      if association.updated?
        association_id = record.public_send(reflection.options[:primary_key] || :id)
        self[reflection.foreign_key] = association_id
        association.loaded!
      end
      saved if autosave
    end
  end
end

def save_collection_association(reflection)

ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
This all happens inside a transaction, _if_ the Transactions module is included into

with #mark_for_destruction.
In addition, it destroys all children that were marked for destruction

:autosave is enabled on the association.
Saves any new associated records, or all loaded autosave associations if
def save_collection_association(reflection)
  if association = association_instance_get(reflection.name)
    autosave = reflection.options[:autosave]
    # By saving the instance variable in a local variable,
    # we make the whole callback re-entrant.
    new_record_before_save = @new_record_before_save
    # reconstruct the scope now that we know the owner's id
    association.reset_scope
    if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
      if autosave
        records_to_destroy = records.select(&:marked_for_destruction?)
        records_to_destroy.each { |record| association.destroy(record) }
        records -= records_to_destroy
      end
      records.each do |record|
        next if record.destroyed?
        saved = true
        if autosave != false && (new_record_before_save || record.new_record?)
          association.set_inverse_instance(record)
          if autosave
            saved = association.insert_record(record, false)
          elsif !reflection.nested?
            association_saved = association.insert_record(record)
            if reflection.validate?
              errors.add(reflection.name) unless association_saved
              saved = association_saved
            end
          end
        elsif autosave
          saved = record.save(validate: false)
        end
        raise(RecordInvalid.new(association.owner)) unless saved
      end
    end
  end
end

def save_has_one_association(reflection)

ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
This all happens inside a transaction, _if_ the Transactions module is included into

destruction with #mark_for_destruction.
In addition, it will destroy the association if it was marked for

on the association.
Saves the associated record if it's new or :autosave is enabled
def save_has_one_association(reflection)
  association = association_instance_get(reflection.name)
  record      = association && association.load_target
  if record && !record.destroyed?
    autosave = reflection.options[:autosave]
    if autosave && record.marked_for_destruction?
      record.destroy
    elsif autosave != false
      key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
      if (autosave && record.changed_for_autosave?) || _record_changed?(reflection, record, key)
        unless reflection.through_reflection
          record[reflection.foreign_key] = key
          association.set_inverse_instance(record)
        end
        saved = record.save(validate: !autosave)
        raise ActiveRecord::Rollback if !saved && autosave
        saved
      end
    end
  end
end

def validate_collection_association(reflection)

+reflection+.
:autosave is turned on for the association specified by
Validate the associated records if :validate or
def validate_collection_association(reflection)
  if association = association_instance_get(reflection.name)
    if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
      records.each_with_index { |record, index| association_valid?(reflection, record, index) }
    end
  end
end

def validate_single_association(reflection)

turned on for the association.
Validate the association if :validate or :autosave is
def validate_single_association(reflection)
  association = association_instance_get(reflection.name)
  record      = association && association.reader
  association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
end