【问题标题】:counter_cache not decrementing for has_many associations in ActiveReord对于 ActiveReord 中的 has_many 关联,counter_cache 没有递减
【发布时间】:2020-04-01 17:30:17
【问题描述】:

我的 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中的User/Show关联,而且还删除了Show对象本身,这不是我想要的。

这种场景中的 counter_cache 不适合使用吗?

早在 2009 年,似乎就有一个 discussion 将此作为一个错误,并讨论了修复,但我仍然在最新的 Rails 3.0 中看到了这个问题。

我只想在模型中编写自己的自定义处理,但似乎没有我可以挂钩的 after_delete 回调(大概这就是递减首先不起作用的原因)。现在,我自己的代码中只有一个地方可能会删除关联,所以我将手动调用来更新计数器,但这似乎是 ActiceRecord 与 counter_cache 关联的一个基本缺点或错误,我想知道我是否只是错过了一些东西。

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

【问题讨论】:

    标签: ruby-on-rails activerecord counter-cache


    【解决方案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

    【讨论】:

    • 谢谢,凯恩。我还没有机会尝试这个,但它看起来确实很有帮助。
    【解决方案2】:

    在 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-08
      • 2015-11-23
      • 2011-07-12
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多