aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/autosave_association.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/autosave_association.rb')
-rw-r--r--activerecord/lib/active_record/autosave_association.rb52
1 files changed, 31 insertions, 21 deletions
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index c1bc8423a9..8f37fcd515 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -158,7 +158,7 @@ module ActiveRecord
def add_autosave_association_callbacks(reflection)
save_method = "autosave_associated_records_for_#{reflection.name}"
validation_method = "validate_associated_records_for_#{reflection.name}"
- validate validation_method
+ force_validation = (reflection.options[:validate] == true || reflection.options[:autosave] == true)
case reflection.macro
when :has_many, :has_and_belongs_to_many
@@ -169,7 +169,10 @@ module ActiveRecord
after_create save_method
after_update save_method
- define_method(validation_method) { validate_collection_association(reflection) }
+ if force_validation || (reflection.macro == :has_many && reflection.options[:validate] != false)
+ define_method(validation_method) { validate_collection_association(reflection) }
+ validate validation_method
+ end
else
case reflection.macro
when :has_one
@@ -179,7 +182,11 @@ module ActiveRecord
define_method(save_method) { save_belongs_to_association(reflection) }
before_save save_method
end
- define_method(validation_method) { validate_single_association(reflection) }
+
+ if force_validation
+ define_method(validation_method) { validate_single_association(reflection) }
+ validate validation_method
+ end
end
end
end
@@ -223,10 +230,8 @@ module ActiveRecord
# Validate the association if <tt>:validate</tt> or <tt>:autosave</tt> is
# turned on for the association specified by +reflection+.
def validate_single_association(reflection)
- if reflection.options[:validate] == true || reflection.options[:autosave] == true
- if (association = association_instance_get(reflection.name)) && !association.target.nil?
- association_valid?(reflection, association)
- end
+ if (association = association_instance_get(reflection.name)) && !association.target.nil?
+ association_valid?(reflection, association)
end
end
@@ -234,7 +239,7 @@ module ActiveRecord
# <tt>:autosave</tt> is turned on for the association specified by
# +reflection+.
def validate_collection_association(reflection)
- if reflection.options[:validate] != false && association = association_instance_get(reflection.name)
+ if association = association_instance_get(reflection.name)
if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave])
records.each { |record| association_valid?(reflection, record) }
end
@@ -243,15 +248,15 @@ module ActiveRecord
# Returns whether or not the association is valid and applies any errors to
# the parent, <tt>self</tt>, if it wasn't. Skips any <tt>:autosave</tt>
- # enabled records if they're marked_for_destruction?.
+ # enabled records if they're marked_for_destruction? or destroyed.
def association_valid?(reflection, association)
+ return true if association.destroyed? || association.marked_for_destruction?
+
unless valid = association.valid?
if reflection.options[:autosave]
- unless association.marked_for_destruction?
- association.errors.each do |attribute, message|
- attribute = "#{reflection.name}_#{attribute}"
- errors[attribute] << message if errors[attribute].empty?
- end
+ association.errors.each do |attribute, message|
+ attribute = "#{reflection.name}_#{attribute}"
+ errors[attribute] << message if errors[attribute].empty?
end
else
errors.add(reflection.name)
@@ -281,9 +286,11 @@ module ActiveRecord
if records = associated_records_to_validate_or_save(association, @new_record_before_save, autosave)
records.each do |record|
+ next if record.destroyed?
+
if autosave && record.marked_for_destruction?
association.destroy(record)
- elsif @new_record_before_save || record.new_record?
+ elsif autosave != false && (@new_record_before_save || record.new_record?)
if autosave
association.send(:insert_record, record, false, false)
else
@@ -309,14 +316,17 @@ module ActiveRecord
# This all happens inside a transaction, _if_ the Transactions module is included into
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
def save_has_one_association(reflection)
- if (association = association_instance_get(reflection.name)) && !association.target.nil?
+ if (association = association_instance_get(reflection.name)) && !association.target.nil? && !association.destroyed?
autosave = reflection.options[:autosave]
if autosave && association.marked_for_destruction?
association.destroy
- elsif new_record? || association.new_record? || association[reflection.primary_key_name] != id || autosave
- association[reflection.primary_key_name] = id
- association.save(!autosave)
+ else
+ key = reflection.options[:primary_key] ? send(reflection.options[:primary_key]) : id
+ if autosave != false && (new_record? || association.new_record? || association[reflection.primary_key_name] != key || autosave)
+ association[reflection.primary_key_name] = key
+ association.save(!autosave)
+ end
end
end
end
@@ -330,12 +340,12 @@ module ActiveRecord
# This all happens inside a transaction, _if_ the Transactions module is included into
# ActiveRecord::Base after the AutosaveAssociation module, which it does by default.
def save_belongs_to_association(reflection)
- if association = association_instance_get(reflection.name)
+ if (association = association_instance_get(reflection.name)) && !association.destroyed?
autosave = reflection.options[:autosave]
if autosave && association.marked_for_destruction?
association.destroy
- else
+ elsif autosave != false
association.save(!autosave) if association.new_record? || autosave
if association.updated?