【问题标题】:Rails 4: counter_cache in has_many :through association with dependent: :destroyRails 4:has_many 中的 counter_cache :通过与依赖项关联::destroy
【发布时间】:2015-11-23 09:16:12
【问题描述】:

尽管已经提出了类似的问题:

它们都没有真正解决我的问题。

我有三个模型,有一个 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

join Administration 模型具有以下属性:

id
user_id
calendar_id
role

我想计算每个user 有多少个calendars,每个calendar 有多少个users。

我打算使用 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 表的相应迁移。)

但后来,我偶然发现了this warning in Rails Guides:

4.1.2.4:依赖

如果您将 :dependent 选项设置为:

  • :destroy,当对象被销毁时,会在其关联对象上调用destroy。
  • :delete,当对象被销毁时,其所有关联对象将直接从数据库中删除,而不调用它们的 销毁方法。

您不应该在 belongs_to 关联上指定此选项,该关联是 与另一个类的 has_many 关联连接。这样做可以 导致数据库中的孤立记录。

因此,计算每个user 有多少个calendars 以及每个calendar 有多少个users 是一个好的做法?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 has-many-through counter-cache


    【解决方案1】:

    好吧,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指的是什么?
    • 谢谢,这更清楚了。所以,你建议我彻底删除dependant: :destroy?
    • 是的,因为dependant: :destroy 执行相同的功能,它会在销毁时销毁关联的记录。同时,您在这里手动操作,但保留 counter_cache
    • 将User.delete_all(:calendar_id =&gt; self.id) 替换为Administration.delete_all(calendar_id: self.id)。
    • 你们说的是依赖...不是依赖。
    猜你喜欢
    • 1970-01-01
    • 2012-04-19
    • 2016-10-03
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 2023-03-07
    • 1970-01-01
    相关资源
    最近更新 更多