From bb78af73ab7e86fd9662e8810e346b082a1ae193 Mon Sep 17 00:00:00 2001 From: claudiob Date: Sun, 14 Dec 2014 22:10:15 -0800 Subject: Deprecate `false` as the way to halt AR callbacks Before this commit, returning `false` in an ActiveRecord `before_` callback such as `before_create` would halt the callback chain. After this commit, the behavior is deprecated: will still work until the next release of Rails but will also display a deprecation warning. The preferred way to halt a callback chain is to explicitly `throw(:abort)`. --- activerecord/lib/active_record/associations/has_many_association.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/associations/has_many_association.rb') diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index d7f655d00c..2a782c06d0 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -17,7 +17,7 @@ module ActiveRecord unless empty? record = klass.human_attribute_name(reflection.name).downcase owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record) - false + throw(:abort) end else -- cgit v1.2.3 From 1152219fa2d7968f864b3a5ebb78d2f95ca4fb5c Mon Sep 17 00:00:00 2001 From: Sean Griffin Date: Mon, 26 Jan 2015 12:37:29 -0700 Subject: Improve consistency of counter caches updating in memory When we made sure that the counter gets updated in memory, we only did it on the has many side. The has many side only does the update if the belongs to cannot. The belongs to side was updated to update the counter cache (if it is able). This means that we need to check if the belongs_to is able to update in memory on the has_many side. We also found an inconsistency where the reflection names were used to grab the association which should update the counter cache. Since reflection names are now strings, this means it was using a different instance than the one which would have the inverse instance set. Fixes #18689 [Sean Griffin & anthonynavarre] --- .../associations/has_many_association.rb | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'activerecord/lib/active_record/associations/has_many_association.rb') diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 2a782c06d0..b574185561 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -101,7 +101,7 @@ module ActiveRecord end def update_counter_in_memory(difference, reflection = reflection()) - if has_cached_counter?(reflection) + if counter_must_be_updated_by_has_many?(reflection) counter = cached_counter_attribute_name(reflection) owner[counter] += difference owner.send(:clear_attribute_changes, counter) # eww @@ -118,18 +118,28 @@ module ActiveRecord # it will be decremented twice. # # Hence this method. - def inverse_updates_counter_cache?(reflection = reflection()) + def inverse_which_updates_counter_cache(reflection = reflection()) counter_name = cached_counter_attribute_name(reflection) - inverse_updates_counter_named?(counter_name, reflection) + inverse_which_updates_counter_named(counter_name, reflection) end + alias inverse_updates_counter_cache? inverse_which_updates_counter_cache - def inverse_updates_counter_named?(counter_name, reflection = reflection()) - reflection.klass._reflections.values.any? { |inverse_reflection| + def inverse_which_updates_counter_named(counter_name, reflection) + reflection.klass._reflections.values.find { |inverse_reflection| inverse_reflection.belongs_to? && inverse_reflection.counter_cache_column == counter_name } end + def inverse_updates_counter_in_memory?(reflection) + inverse = inverse_which_updates_counter_cache(reflection) + inverse && inverse == reflection.inverse_of + end + + def counter_must_be_updated_by_has_many?(reflection) + !inverse_updates_counter_in_memory?(reflection) && has_cached_counter?(reflection) + end + def delete_count(method, scope) if method == :delete_all scope.delete_all -- cgit v1.2.3