diff options
Diffstat (limited to 'activerecord/lib/active_record/associations/has_many_association.rb')
-rw-r--r-- | activerecord/lib/active_record/associations/has_many_association.rb | 83 |
1 files changed, 65 insertions, 18 deletions
diff --git a/activerecord/lib/active_record/associations/has_many_association.rb b/activerecord/lib/active_record/associations/has_many_association.rb index 72e0891702..93084e0dcf 100644 --- a/activerecord/lib/active_record/associations/has_many_association.rb +++ b/activerecord/lib/active_record/associations/has_many_association.rb @@ -41,6 +41,14 @@ module ActiveRecord end end + def empty? + if has_cached_counter? + size.zero? + else + super + end + end + private # Returns the number of records in this collection. @@ -58,7 +66,7 @@ module ActiveRecord # the loaded flag is set to true as well. def count_records count = if has_cached_counter? - owner.send(:read_attribute, cached_counter_attribute_name) + owner._read_attribute cached_counter_attribute_name else scope.count end @@ -71,20 +79,31 @@ module ActiveRecord [association_scope.limit_value, count].compact.min end - def has_cached_counter?(reflection = reflection) + def has_cached_counter?(reflection = reflection()) owner.attribute_present?(cached_counter_attribute_name(reflection)) end - def cached_counter_attribute_name(reflection = reflection) + def cached_counter_attribute_name(reflection = reflection()) options[:counter_cache] || "#{reflection.name}_count" end - def update_counter(difference, reflection = reflection) + def update_counter(difference, reflection = reflection()) + update_counter_in_database(difference, reflection) + update_counter_in_memory(difference, reflection) + end + + def update_counter_in_database(difference, reflection = reflection()) if has_cached_counter?(reflection) counter = cached_counter_attribute_name(reflection) owner.class.update_counters(owner.id, counter => difference) + end + end + + def update_counter_in_memory(difference, reflection = reflection()) + if has_cached_counter?(reflection) + counter = cached_counter_attribute_name(reflection) owner[counter] += difference - owner.changed_attributes.delete(counter) # eww + owner.send(:clear_attribute_changes, counter) # eww end end @@ -98,30 +117,39 @@ module ActiveRecord # it will be decremented twice. # # Hence this method. - def inverse_updates_counter_cache?(reflection = reflection) + def inverse_updates_counter_cache?(reflection = reflection()) counter_name = cached_counter_attribute_name(reflection) - reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection| + inverse_updates_counter_named?(counter_name, reflection) + end + + def inverse_updates_counter_named?(counter_name, reflection = reflection()) + reflection.klass._reflections.values.any? { |inverse_reflection| + inverse_reflection.belongs_to? && inverse_reflection.counter_cache_column == counter_name } end + def delete_count(method, scope) + if method == :delete_all + scope.delete_all + else + scope.update_all(reflection.foreign_key => nil) + end + end + + def delete_or_nullify_all_records(method) + count = delete_count(method, self.scope) + update_counter(-count) + end + # Deletes the records according to the <tt>:dependent</tt> option. def delete_records(records, method) if method == :destroy records.each(&:destroy!) update_counter(-records.length) unless inverse_updates_counter_cache? else - if records == :all - scope = self.scope - else - scope = self.scope.where(reflection.klass.primary_key => records) - end - - if method == :delete_all - update_counter(-scope.delete_all) - else - update_counter(-scope.update_all(reflection.foreign_key => nil)) - end + scope = self.scope.where(reflection.klass.primary_key => records) + update_counter(-delete_count(method, scope)) end end @@ -132,6 +160,25 @@ module ActiveRecord false end end + + def concat_records(records, *) + update_counter_if_success(super, records.length) + end + + def _create_record(attributes, *) + if attributes.is_a?(Array) + super + else + update_counter_if_success(super, 1) + end + end + + def update_counter_if_success(saved_successfully, difference) + if saved_successfully + update_counter_in_memory(difference) + end + saved_successfully + end end end end |