对于 ActiveReord 中的 has_many 关联,counter_cache 不会递减

发布于 2024-09-27 01:24:49 字数 1189 浏览 1 评论 0原文

我的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

江挽川 2024-10-04 01:24:49

在 Rails 5 中遇到了相关问题(通过连接表使用自引用计数器缓存)并按如下方式修复:

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]

在标准 has_many 上通过关系:

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

必须在两侧指定计数器缓存,否则我们不会在关系删除时递减

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

清浅ˋ旧时光 2024-10-04 01:24:49

这里有同样的问题,但在 Rails 2.3 上。
值得注意的是,还添加了一些内容,例如:

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

不会更新计数器缓存,也不会更新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:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文