Rails 4: counter_cache в has_many: через ассоциацию с зависимым:: destroy

Хотя подобные вопросы уже задавали:

ни один из них на самом деле не решает мою проблему.

У меня есть три модели с has_many: через ассоциацию:

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

Я хотел бы посчитать, сколько calendars у каждого user и сколько users у каждого calendar.

Я собирался использовать 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 Guides:

4.1.2.4: зависимый

Если вы установите для параметра: зависимые значения:

  • : destroy, когда объект уничтожен, destroy будет вызываться для связанных с ним объектов.
  • : delete, при уничтожении объекта все связанные с ним объекты будут удалены непосредственно из базы данных без вызова их метода уничтожения.

Не следует указывать эту опцию для ассоциации own_to, которая связана с ассоциацией has_many в другом классе. Это может привести к тому, что записи в вашей базе данных станут потерянными.

Следовательно, что было бы хорошей практикой, чтобы подсчитать, сколько calendars у каждого user и сколько users у каждого calendar?


person Thibaud Clement    schedule 28.08.2015    source источник


Ответы (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.

person Raza    schedule 28.08.2015
comment
Спасибо. Похоже на интересное решение. Один вопрос: что означает :question_id? - person Thibaud Clement; 28.08.2015
comment
Спасибо, это понятнее. Итак, вы рекомендуете полностью удалить dependant: :destroy? - person Thibaud Clement; 28.08.2015
comment
да, поскольку dependant: :destroy выполняет ту же функцию, он уничтожает связанные записи при уничтожении. а здесь вы делаете это вручную, но сохраняете counter_cache - person Raza; 28.08.2015
comment
Замените User.delete_all(:calendar_id => self.id) на Administration.delete_all(calendar_id: self.id). - person dadachi; 20.10.2015
comment
Вы, ребята, говорите о зависимости ... не о зависимости. - person IAmNaN; 20.10.2016