Rails 4: 在具有dependent: :destroy的has_many :through关联中使用counter_cache

4

虽然已经有类似的问题被提出:

但是它们都没有解决我的问题。

我有三个模型,使用 has_many :through 关联:

class User < ActiveRecord::Base
  has_many :administrations
  has_many :calendars, through: :administrations
end

class Calendar < ActiveRecord::Base
  has_many :administrations
  has_many :users, through: :administrations
end

class Administration < ActiveRecord::Base
  belongs_to :user
  belongs_to :calendar
end

加入管理模型具有以下属性:
id
user_id
calendar_id
role

我希望能够计算每个用户拥有多少个日历,以及每个日历被多少用户所拥有。我原本想使用如下的counter_cache方法:
class Administration < ActiveRecord::Base
  belongs_to :user, counter_cache: :count_of_calendars
  belongs_to :calendar, counter_cache: :count_of_users
end

(当然,还需要相应的迁移来将:count_of_calendars添加到users表中,将:count_of_users添加到calendars表中。)
但是,我在Rails指南中发现了这个警告
引用: 4.1.2.4:dependent 如果您将:dependent选项设置为: :destroy,当对象被销毁时,将调用其关联对象上的destroy。 :delete,在销毁对象时,所有关联对象将直接从数据库中删除,而不调用它们的destroy方法。 您不应该在belongs_to关联上指定此选项,该关联与其他类上的has_many关联相连接。这样做可能导致数据库中的孤立记录。 因此,计算每个用户拥有多少个calendars和每个calendar拥有多少个users的良好实践是什么?
1个回答

3

如果使用dependent: :destroy,会删除相关记录,但不会更新counter_cache,因此可能会导致counter_cache中的计数错误。相反,您可以实现一个回调函数来删除关联记录,并更新您的counter_cache

class Calendar < ActiveRecord::Base

  has_many :administrations
  has_many :users, through: :administrations


  before_destroy :delete_dependents

  private
  def delete_dependents
    user_ids = self.user_ids
    User.delete_all(:calendar_id => self.id)
    user_ids.each do |u_id|
      Calendar.reset_counters u_id, :users
    end
  end
end

同样地,也要为 User 模型实现这个功能。

谢谢。听起来是一个有趣的解决方案。但我有一个问题::question_id是指什么? - Thibaud Clement
谢谢,现在更清楚了。所以,您建议我完全删除 dependant: :destroy 吗? - Thibaud Clement
是的,dependant: :destroy 执行相同的功能,它在销毁时销毁关联记录。而在这里,您正在手动执行此操作,但保留了 counter_cache。 - Raza
Administration.delete_all(calendar_id: self.id) 替换 User.delete_all(:calendar_id => self.id) - dadachi
你们在谈论 dependent,而不是 dependant。 - IAmNaN

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