К сожалению, люди продолжают использовать has_and_belongs_to_many
, хотя это приводит к разного рода таким сиротам. Отношение has_many ..., :through
может быть помечено :dependent => :destroy
для автоматической очистки неиспользуемых детей. Как правило, у вас есть неиспользуемые записи о присоединении, и удалить их неприятно.
Что вы можете сделать, это подойти с точки зрения SQL, поскольку has_and_belongs_to_many
записи недоступны, если их родительские записи больше не определены. Они просто не существуют в том, что касается ActiveRecord. Использование модели соединения означает, что вы всегда можете получить доступ к этим данным, поскольку им выдаются собственные идентификаторы.
has_and_belongs_to_many
отношения основаны на составном ключе, что делает удаление их серьезным неудобством. Обычно вы делаете DELETE FROM table WHERE id IN (...) AND ...
и уверены, что удаляются только целевые записи. С составным ключом вы не можете сделать это.
Вы можете найти эти работы для примера отношения тега к элементу:
DELETE FROM item_tags, tags, items WHERE item_tags.tag_id=tags.id AND item_tags.item_id=items.id AND tags.id IS NULL AND items.id IS NULL
Оператор DELETE
может быть действительно конкретным относительно того, как он работает, и не дает такой же широты, как SELECT
с объединениями, которые могут быть определены как левые или правые, внутренние или внешние, как требуется.
Если у вас есть первичный идентификационный ключ в таблице соединений, вы можете легко это сделать:
DELETE FROM item_tags WHERE id IN (SELECT id FROM item_tags LEFT JOIN tags ON item_tags.tag_id=tags.id LEFT JOIN items ON item_tags.item_id=items.id WHERE tags.id IS NULL AND items.id IS NULL)
На самом деле, может быть полезно добавить первичный ключ в таблицу отношений, даже если ActiveRecord его игнорирует.
Edit:
Что касается проблемы с вашим модулем, если вы застряли с таким подходом:
module CleanupMethods
def cleanup
# ...
end
end
class Tag
# Import the module methods as class methods
extend CleanupMethods
end
Если вы используете столбец счетного кэша, вы можете сделать это намного проще, но вам также нужно будет убедиться, что ваши счетные кэши точны.