Rails 4: counter_cache in has_many :through association with dependent: :destroy

北战南征 提交于 2020-01-11 09:54:09

问题


Although similar questions have already been asked:

  • counter_cache with has_many :through
  • dependent => destroy on a "has_many through" association
  • has_many :through with counter_cache

none of them actually addresses my issue.

I have three models, with a has_many :through association :

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

The join Administration model has the following attributes:

id
user_id
calendar_id
role

I would like to count how many calendars each user has and how many users each calendar has.

I was going to go with counter_cache as follows:

class Administration < ActiveRecord::Base
  belongs_to :user, counter_cache: :count_of_calendars
  belongs_to :calendar, counter_cache: :count_of_users
end

(and, of course, the corresponding migrations to add :count_of_calendars to the users table and :count_of_users to the calendars table.)

But then, I stumbled upon this warning in Rails Guides:

4.1.2.4 :dependent

If you set the :dependent option to:

  • :destroy, when the object is destroyed, destroy will be called on its associated objects.
  • :delete, when the object is destroyed, all its associated objects will be deleted directly from the database without calling their destroy method.

You should not specify this option on a belongs_to association that is connected with a has_many association on the other class. Doing so can lead to orphaned records in your database.

Therefore, what would be a good practice to count how many calendars each user has and how many users each calendar has?


回答1:


Well, dependent: :destroy will destroy the associated records, but it won't update the counter_cache, so you may have wrong count in counter_cache. Instead you can implement a callback that will destroy the associated records, and update your 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

And similarly, implement this for User model too



来源:https://stackoverflow.com/questions/32275640/rails-4-counter-cache-in-has-many-through-association-with-dependent-destroy

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!