ActiveRecord中has_many关联的counter_cache未递减

4

我的 Rails 3 应用有两个模型,第三个模型是它们之间的连接表,并具有它们的 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中的User/Show关联,还会删除Show对象本身,这不是我想要的。

在这种情况下,计数器缓存是否不适合使用?

2009年有关此问题的讨论,并且讨论了修复方法,但我仍然在最新的Rails 3.0中看到这个问题。

我只想在模型中编写自己的处理方式,但似乎没有after_delete回调函数可以连接(这可能是减量不起作用的原因)。目前,只有我的代码中有一个删除关联的地方,所以我将手动调用更新计数器,但这似乎是ActiceRecord关联与counter_cache的根本缺陷或错误,我想知道是否遗漏了什么。

如果这确实是counter_cache的真正问题,最好的解决方法是什么?

2个回答

3

我在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 through 关联中:

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

计数器缓存必须在双方都指定,否则在删除关系时它不会被减少。

1

我也遇到了同样的问题,但是在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-on-join-model-correctly#ticket-2824-18


谢谢,kain。我还没有机会尝试这个,但它看起来肯定很有帮助。 - Joost Schuur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接