对于 ActiveReord 中的 has_many 关联,counter_cache 不会递减
我的 Rails 3 应用程序有 2 个模型,第三个模型是它们之间的联接表及其 has_many 关系。基本上,User 和 Show 通过 SavedShow 连接起来,允许用户保存节目列表:
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
我注意到 counter_cache 字段 (shows_saved_count) 会自动递增,但不会递减。问题的核心似乎是从用户列表中删除节目是通过删除完成的,这不会触发 counter_cache 的更新:
current_user.shows.delete(@show)
但是,我不能在这里调用 destroy 方法,因为这不仅删除了用户/节目SavedShow 中的关联,还有 Show 对象本身,这不是我想要的。
在这种情况下使用 counter_cache 不合适吗?
似乎有一个关于讨论这是 2009 年的一个错误,并讨论了修复,但我仍然在最新的 Rails 3.0 中看到这个问题。
我只会在模型中编写自己的自定义处理,但似乎没有可以挂钩的 after_delete 回调(大概这就是递减首先不起作用的原因)。现在,我自己的代码中只有一个地方可能会删除关联,因此我只需手动调用来更新计数器,但这似乎是 ActiceRecord 与 counter_cache 关联的一个基本缺点或错误,我想知道我是否只是错过了一些东西。
如果这确实是 counter_caches 的真正问题,那么最好的解决方法是什么?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在 Rails 5 中遇到了相关问题(通过连接表使用自引用计数器缓存)并按如下方式修复:
https://guides.rubyonrails.org/association_basics.html#options-for-has-many-counter-cache
[RAILS 6]
在标准 has_many 上通过关系:
必须在两侧指定计数器缓存,否则我们不会在关系删除时递减
Faced a related issue in Rails 5 (with self referential counter cache through a join table) and fixed it as below:
https://guides.rubyonrails.org/association_basics.html#options-for-has-many-counter-cache
[RAILS 6]
On a standard has_many through relation :
The counter cache has to be specified on both sides, otherwise it won't we decremented on relation deletion
这里有同样的问题,但在 Rails 2.3 上。
值得注意的是,还添加了一些内容,例如:
不会更新计数器缓存,也不会更新association.delete(object)上的相关updated_at字段。
为了解决这个问题,我们通常会操纵连接模型,但这也有一些缺点。
补丁在这里:https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/2824-patch-has_many-through-doesnt-update-counter_cache -正确加入模型#ticket-2824-18
Same issues here but on Rails 2.3.
Worth noticing that also adding a touch, like:
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