Правильный способ удаления has_many: через записи объединений?

class Post < ActiveRecord::Base
  has_many :posts_tags
  has_many :tags, through: :posts_tags
end

class PostsTag < ActiveRecord::Base
  belongs_to :post
  belongs_to :tag
end

class Tag < ActiveRecord::Base
  has_many :posts_tags
  has_many :posts, through: :posts_tags
end

Когда сообщение будет уничтожено, я хочу, чтобы все его ассоциации также были удалены. Я НЕ хочу, чтобы проверки на модели PostsTag выполнялись. Я просто хочу удалить.

Я обнаружил, что добавление зависимости от отношения к тегам сообщений из модели Post работает так, как я хочу: has_many :posts_tags, dependent: :delete_all.

Однако документация по этому вопросу, похоже, предполагает, что я должен сделать это вместо: has_many :tags, through: :posts_tags, dependent: :delete_all. Когда я это делаю, объект Tag уничтожается и объект объединения остается.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

Для has_many, destroy всегда будет вызывать метод уничтожения удаляемой записи (ов), чтобы выполнялись обратные вызовы. Однако удаление будет либо выполнять удаление в соответствии со стратегией, заданной опцией: зависимый, либо если нет: зависимая опция указана, то она будет следовать стратегии по умолчанию. Стратегия по умолчанию: nullify (установить внешние ключи в nil), , за исключением has_many: through, где стратегия по умолчанию - delete_all (удалить записи объединения, не выполняя их обратные вызовы).

  • Как я могу использовать стандартную стратегию по умолчанию? Если я уйду: полностью зависеть, записи вообще не удаляются. И я не могу просто указать: зависит от отношения has_many. Rails возвращается и говорит: "Игнорируемый вариант ожидает либо: destroy,: delete_all,: nullify или: restrict ({})".
  • Если я не укажу: зависит от любого из отношений, он НЕ сбрасывает значение post_id в объекте PostsTag, поскольку он, кажется, предлагает

Возможно, я читаю это неправильно, и подход, который я нашел, работает правильно?

Ответ 1

Ваше первоначальное представление:

has_many :posts_tags, dependent: :delete_all

- это именно то, что вы хотите. Вы не хотите объявлять это в ассоциации has-many-while :tags, поскольку это уничтожит все связанные теги. То, что вы хотите удалить, это сама ассоциация - это то, что представляет собой модель объединения PostTag.

Итак, почему документы говорят, что они делают? Вы не понимаете сценарий описания документации:

Post.find(1).destroy
Post.find(1).tags.delete

Первый вызов (ваш сценарий) просто уничтожит сообщение. То есть, если вы не укажете стратегию :dependent, как я вам предлагаю. Второй вызов - это то, что описывает документация. Вызов .tags.delete не будет (по умолчанию) фактически уничтожать теги (поскольку к ним присоединяется has-many-through), но связанная модель соединения, которая объединяет эти теги.