Rails counter_cache not updating correctly

前端 未结 5 734
佛祖请我去吃肉
佛祖请我去吃肉 2021-02-04 00:00

Using Rails 3.1.3 and I\'m trying to figure out why our counter caches aren\'t being updated correctly when changing the parent record id via update_attributes.

         


        
5条回答
  •  刺人心
    刺人心 (楼主)
    2021-02-04 00:46

    From the fine manual:

    :counter_cache

    Caches the number of belonging objects on the associate class through the use of increment_counter and decrement_counter. The counter cache is incremented when an object of this class is created and decremented when it’s destroyed.

    There's no mention of updating the cache when an object is moved from one owner to another. Of course, the Rails documentation is often incomplete so we'll have to look at the source for confirmation. When you say :counter_cache => true, you trigger a call to the private add_counter_cache_callbacks method and add_counter_cache_callbacks does this:

    1. Adds an after_create callback which calls increment_counter.
    2. Adds an before_destroy callback which calls decrement_counter.
    3. Calls attr_readonly to make the counter column readonly.

    I don't think you're expecting too much, you're just expecting ActiveRecord to be more complete than it is.

    All is not lost though, you can fill in the missing pieces yourself without too much effort. If you want to allow reparenting and have your counters updated, you can add a before_save callback to your ExhibitorRegistration that adjusts the counters itself, something like this (untested demo code):

    class ExhibitorRegistration < ActiveRecord::Base
      belongs_to :event, :counter_cache => true
      before_save :fix_counter_cache, :if => ->(er) { !er.new_record? && er.event_id_changed? }
    
    private
    
      def fix_counter_cache
        Event.decrement_counter(:exhibitor_registration_count, self.event_id_was)
        Event.increment_counter(:exhibitor_registration_count, self.event_id)
      end
    
    end
    

    If you were adventurous, you could patch something like that into ActiveRecord::Associations::Builder#add_counter_cache_callbacks and submit a patch. The behavior you're expecting is reasonable and I think it would make sense for ActiveRecord to support it.

提交回复
热议问题