Допустим, у вас есть приложение, в котором пользователь может подписаться на журнал.С ассоциациями ActiveRecord это выглядело бы примерно так:
# app/models/subscription.rb
class Subscription < ActiveRecord::Base
belongs_to :magazine
belongs_to :user
end
# app/models/user.rb
class User < ActiveRecord::Base
has_many :subscriptions
has_many :users, through: :subscriptions
end
# app/models/magazine.rb
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :users, through: :subscriptions
end
К сожалению, кто-то забыл добавить зависимые:: destroy в has_many: подписки.Когда пользователь или журнал был удален, оставленная бесхозной подписка осталась позади.
Эта проблема была исправлена зависимыми:: destroy, но все еще оставалось большое количество потерянных записей.Существует два способа удаления потерянных записей.
Подход 1 - Неприятный запах
Subscription.find_each do |subscription|
if subscription.magazine.nil? || subscription.user.nil?
subscription.destroy
end
end
При этом выполняется отдельный SQL-запрос для каждой записи, проверяется, является ли она потерянной, иуничтожает его, если он есть.
Подход 2 - Хороший запах
Subscription.where([
"user_id NOT IN (?) OR magazine_id NOT IN (?)",
User.pluck("id"),
Magazine.pluck("id")
]).destroy_all
Этот подход сначала получает идентификаторы всех пользователей и журналов, а затем выполняет один запрос, чтобы найти все подписки, которые непринадлежат либо пользователю, либо запросу.