counter_cache not decrementing for has_many associations in ActiveReord

非 Y 不嫁゛ 提交于 2021-02-19 03:43:09

问题


My Rails 3 app has 2 models and a third that's join table between them and their has_many relationships. Basically, User and Show are joined by SavedShow, allowing users to save a list of shows:

class Show < ActiveRecord::Base
  has_many :saved_shows
  has_many :users, :through => :saved_shows
end

class User < ActiveRecord::Base
  has_many :saved_shows
  has_many :shows, :through => :saved_shows
end

class SavedShow < ActiveRecord::Base
  belongs_to :user, :counter_cache => :saved_shows_count
  belongs_to :show
end

I've noticed that the counter_cache field (shows_saved_count) gets incremented automatically just fine, but not decremented. The core of the issue seems to be that removing shows from a user's list is done via delete, which does not trigger updating of the counter_cache:

current_user.shows.delete(@show)

However, I can't call the destroy method here, since that not only deleted the User/Show association in SavedShow, but also the Show object itself, which is not what I want.

Is a counter_cache in this kind of scenario not an appropriate use?

There appears to be a discussion about this as a bug back in 2009, and fixes were discussed, but I'm still seeing the issue in the latest Rails 3.0.

I would just write my own custom handling in the model, but there seems to be no after_delete callback that I can hook into (presumably this is the reason decrementing doesn't work in the first place). Right now, there's only one place in my own code where a delete of the association could occur, so I'll just manually make a call to update the counter, but this seems like like such a fundamental shortcoming or bug of ActiceRecord associations with counter_cache, that I'm wondering if I'm not just missing something.

If this is indeed a genuine problem with counter_caches, what would be the best workaround?


回答1:


Same issues here but on Rails 2.3. Worth noticing that also adding a touch, like:

belongs_to :user, :counter_cache => :saved_shows_count, :touch => true

Won't update counter cache nor the related updated_at field on association.delete(object).

To workaround the issue usually we manipulate the join model, but that also have some drawbacks.

Patch is here: https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2824-patch-has_many-through-doesnt-update-counter_cache-on-join-model-correctly#ticket-2824-18




回答2:


Faced a related issue in Rails 5 (with self referential counter cache through a join table) and fixed it as below:

class User < ActiveRecord::Base
  has_many :saved_shows, :counter_cache => :saved_shows_count
  has_many :shows, :through => :saved_shows
end

https://guides.rubyonrails.org/association_basics.html#options-for-has-many-counter-cache

[RAILS 6]

On a standard has_many through relation :

class Parent < ApplicationRecord

has_many :joins,
         foreign_key: :parent_id,
         dependent: :destroy,
         counter_cache: :joins_count

has_many :children, through: :joins, source: 'child'
...


class Join < ApplicationRecord
  belongs_to :parent, counter_cache: :joins_count
  belongs_to :child
end

The counter cache has to be specified on both sides, otherwise it won't we decremented on relation deletion



来源:https://stackoverflow.com/questions/3902995/counter-cache-not-decrementing-for-has-many-associations-in-activereord

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!