Although similar questions have already been asked:
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?
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