diff options
author | Bogdan Gusiev <agresso@gmail.com> | 2015-09-03 16:38:59 +0300 |
---|---|---|
committer | Bogdan Gusiev <agresso@gmail.com> | 2015-09-03 16:38:59 +0300 |
commit | 712fc8a570bc0709c3be5645e9808b0ad8fcfe45 (patch) | |
tree | a76e90ac21ef66f20e1de30b056e24b0b633fd46 /activerecord/lib/active_record/reflection.rb | |
parent | 0294c61359340892f0c38f57b203ba58edbc55e5 (diff) | |
download | rails-712fc8a570bc0709c3be5645e9808b0ad8fcfe45.tar.gz rails-712fc8a570bc0709c3be5645e9808b0ad8fcfe45.tar.bz2 rails-712fc8a570bc0709c3be5645e9808b0ad8fcfe45.zip |
HasManyAssociation: moved half of counter cache code to reflection
Current implementation has a lot of utility methods that accept
reflection call a lot of methods on it and exit.
E.g. has_counter_cache?(reflection)
It causes confusion and inability to cache result of the method even
through it always returns the same result for the same reflection
object.
It can be done easier without access to the association context
by moving code into reflection itself.
e.g. reflection.has_counter_cache?
Reflection is less complex object than association so moving code there
automatically makes it simplier to understand.
Diffstat (limited to 'activerecord/lib/active_record/reflection.rb')
-rw-r--r-- | activerecord/lib/active_record/reflection.rb | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb index 5360db6a19..0394f89623 100644 --- a/activerecord/lib/active_record/reflection.rb +++ b/activerecord/lib/active_record/reflection.rb @@ -94,7 +94,8 @@ module ActiveRecord # @api public def reflect_on_all_associations(macro = nil) association_reflections = reflections.values - macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections + association_reflections.select! { |reflection| reflection.macro == macro } if macro + association_reflections end # Returns the AssociationReflection object for the +association+ (use the symbol). @@ -159,6 +160,54 @@ module ActiveRecord scope_chain.flatten end + def counter_cache_column + if belongs_to? + if options[:counter_cache] == true + "#{active_record.name.demodulize.underscore.pluralize}_count" + elsif options[:counter_cache] + options[:counter_cache].to_s + end + else + options[:counter_cache] ? options[:counter_cache].to_s : "#{name}_count" + end + end + + # This shit is nasty. We need to avoid the following situation: + # + # * An associated record is deleted via record.destroy + # * Hence the callbacks run, and they find a belongs_to on the record with a + # :counter_cache options which points back at our owner. So they update the + # counter cache. + # * In which case, we must make sure to *not* update the counter cache, or else + # it will be decremented twice. + # + # Hence this method. + def inverse_which_updates_counter_cache + return @inverse_which_updates_counter_cache if defined?(@inverse_which_updates_counter_cache) + @inverse_which_updates_counter_cache = klass.reflect_on_all_associations(:belongs_to).find do |inverse| + inverse.counter_cache_column == counter_cache_column + end + end + alias inverse_updates_counter_cache? inverse_which_updates_counter_cache + + def inverse_updates_counter_in_memory? + inverse_of && inverse_which_updates_counter_cache == inverse_of + end + + # Returns whether a counter cache should be used for this association. + # + # The counter_cache option must be given on either the owner or inverse + # association, and the column must be present on the owner. + def has_cached_counter? + options[:counter_cache] || + inverse_which_updates_counter_cache && inverse_which_updates_counter_cache.options[:counter_cache] && + !!active_record.columns_hash[counter_cache_column] + end + + def counter_must_be_updated_by_has_many? + !inverse_updates_counter_in_memory? && has_cached_counter? + end + def alias_candidate(name) "#{plural_name}_#{name}" end @@ -321,14 +370,6 @@ module ActiveRecord @active_record_primary_key ||= options[:primary_key] || primary_key(active_record) end - def counter_cache_column - if options[:counter_cache] == true - "#{active_record.name.demodulize.underscore.pluralize}_count" - elsif options[:counter_cache] - options[:counter_cache].to_s - end - end - def check_validity! check_validity_of_inverse! end |