Предположим, у нас обычные отношения M-M между двумя таблицами, например:
пользователи --- <<strong> users_tags > --- * теги .
В этом посте меня интересует только отношение user_tags, теги: я бы хотел, чтобы связанные теги можно было удалить. Только теги, на которые нет ссылок, могут быть уничтожены.
Глупый способ сделать это будет:
class Tag
def before_destroy
unless self.user_tags.empty?
raise "error"
end
end
end
Но я думаю, что есть потенциальное состояние гонки между проверкой user_tags.empty? и фактическое удаление.
Второй подход может заключаться в блокировке всей таблицы user_tags перед проверкой, остались ли какие-либо ссылки.
И третий способ, который я могу придумать, связан с изменениями в коде, который создает фактическую ссылку:
Добавить ссылку на users_tags:
- Получить тег
- Блокировка (чтобы избежать одновременного уничтожения)
- Создать ссылку в users_tag
- Commit
Тогда обработчик before_destroy может:
- self.lock!
- Проверьте, есть ли ссылки
- уничтожить себя
- Commit
Есть ли лучшие способы сделать это? Какой из них надежный / лучший? Лично я склоняюсь ко второму, так как для него нужна только логика в контроллере before_destroy, но с затратами на блокировку всей таблицы.
Редактировать 1:
Экспериментируя с LOCK TABLE Я понял, что они играют против моих транзакций. При использовании innodb вы можете либо использовать транзакции (и их функции блокировки), либо использовать таблицу LOCK / UNLOCK, сочетание обоих миров делает ситуацию намного хуже (LOCK / UNLOCK вызывает неявные фиксации, я пропустил это предупреждение в документе). Но это только для протокола.
( Редактировать 2 (несколько недель спустя): Я снова решил эту проблему. Поэтому хочу еще раз подчеркнуть Не использовать LOCK TABLE )
Сейчас я стремлюсь использовать SHARE LOCK на родительском объекте (тег в примере)) при добавлении потомков и блокировку FOR UPDATE для удалений. Но мне все еще интересно, так ли это должно быть (заблокируйте Rang в дочерней таблице для обновления в родительской таблице).
Btw. Я также понимаю, что этот вопрос теперь полностью независим от рельсов:).