aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib
diff options
context:
space:
mode:
authorEloy Duran <eloy.de.enige@gmail.com>2009-12-15 16:40:02 +0100
committerEloy Duran <eloy.de.enige@gmail.com>2009-12-28 16:56:31 +0100
commit9c771a9608f54ebdfcb6fca819c83038489ce50d (patch)
tree818d29c435d32311a2b02fc990d7be0ac012d0df /activerecord/lib
parentff508640e28914da2b546f6a8c9f215bab201b61 (diff)
downloadrails-9c771a9608f54ebdfcb6fca819c83038489ce50d.tar.gz
rails-9c771a9608f54ebdfcb6fca819c83038489ce50d.tar.bz2
rails-9c771a9608f54ebdfcb6fca819c83038489ce50d.zip
Make sure to not add autosave callbacks multiple times. [#3575 state:resolved]
This makes sure that, in a HABTM association, only one join record is craeted.
Diffstat (limited to 'activerecord/lib')
-rw-r--r--activerecord/lib/active_record/autosave_association.rb40
-rw-r--r--activerecord/lib/active_record/nested_attributes.rb4
2 files changed, 27 insertions, 17 deletions
diff --git a/activerecord/lib/active_record/autosave_association.rb b/activerecord/lib/active_record/autosave_association.rb
index c0d8904bc8..44c668b619 100644
--- a/activerecord/lib/active_record/autosave_association.rb
+++ b/activerecord/lib/active_record/autosave_association.rb
@@ -155,6 +155,13 @@ module ActiveRecord
# Adds a validate and save callback for the association as specified by
# the +reflection+.
+ #
+ # For performance reasons, we don't check whether to validate at runtime,
+ # but instead only define the method and callback when needed. However,
+ # this can change, for instance, when using nested attributes. Since we
+ # don't want the callbacks to get defined multiple times, there are
+ # guards that check if the save or validation methods have already been
+ # defined before actually defining them.
def add_autosave_association_callbacks(reflection)
save_method = "autosave_associated_records_for_#{reflection.name}"
validation_method = "validate_associated_records_for_#{reflection.name}"
@@ -162,28 +169,33 @@ module ActiveRecord
case reflection.macro
when :has_many, :has_and_belongs_to_many
- before_save :before_save_collection_association
+ unless method_defined?(save_method)
+ before_save :before_save_collection_association
- define_method(save_method) { save_collection_association(reflection) }
- # Doesn't use after_save as that would save associations added in after_create/after_update twice
- after_create save_method
- after_update save_method
+ define_method(save_method) { save_collection_association(reflection) }
+ # Doesn't use after_save as that would save associations added in after_create/after_update twice
+ after_create save_method
+ after_update save_method
+ end
- if force_validation || (reflection.macro == :has_many && reflection.options[:validate] != false)
+ if !method_defined?(validation_method) &&
+ (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
- define_method(save_method) { save_has_one_association(reflection) }
- after_save save_method
- when :belongs_to
- define_method(save_method) { save_belongs_to_association(reflection) }
- before_save save_method
+ unless method_defined?(save_method)
+ case reflection.macro
+ when :has_one
+ define_method(save_method) { save_has_one_association(reflection) }
+ after_save save_method
+ when :belongs_to
+ define_method(save_method) { save_belongs_to_association(reflection) }
+ before_save save_method
+ end
end
- if force_validation
+ if !method_defined?(validation_method) && force_validation
define_method(validation_method) { validate_single_association(reflection) }
validate validation_method
end
diff --git a/activerecord/lib/active_record/nested_attributes.rb b/activerecord/lib/active_record/nested_attributes.rb
index ca3110a374..386f0e7ca7 100644
--- a/activerecord/lib/active_record/nested_attributes.rb
+++ b/activerecord/lib/active_record/nested_attributes.rb
@@ -235,7 +235,7 @@ module ActiveRecord
end
reflection.options[:autosave] = true
-
+ add_autosave_association_callbacks(reflection)
self.nested_attributes_options[association_name.to_sym] = options
if options[:reject_if] == :all_blank
@@ -250,8 +250,6 @@ module ActiveRecord
assign_nested_attributes_for_#{type}_association(:#{association_name}, attributes)
end
}, __FILE__, __LINE__
-
- add_autosave_association_callbacks(reflection)
else
raise ArgumentError, "No association found for name `#{association_name}'. Has it been defined yet?"
end