Поиск nil has_one ассоциаций в том, где запрос
Это может быть простой вопрос, но я, кажется, вытаскиваю свои волосы, чтобы найти здесь элегантное решение. У меня есть два класса модели ActiveRecord с ассоциацией has_one и belongs_to между ними:
class Item < ActiveRecord::Base
has_one :purchase
end
class Purchase < ActiveRecord::Base
belongs_to :item
end
Я ищу элегантный способ найти все объекты Item, у которых нет связанного с ними объекта покупки, в идеале, не прибегая к использованию логического is_purchased
или аналогичного атрибута для элемента.
Сейчас у меня есть:
purchases = Purchase.all
Item.where('id not in (?)', purchases.map(&:item_id))
Что работает, но мне кажется неэффективным, поскольку он выполняет два запроса (и покупки могут быть массивными наборами записей).
Running Rails 3.1.0
Ответы
Ответ 1
Это довольно распространенная задача, SQL OUTER JOIN обычно отлично подходит для нее. Посмотрите здесь, например.
В этом случае попробуйте использовать что-то вроде
not_purchased_items = Item.joins("LEFT OUTER JOIN purchases ON purchases.item_id = items.id").where("purchases.id IS null")
Ответ 2
Нашли два других пути, которые можно было сделать:
Item.includes(:purchase).references(:purchase).where("purchases.id IS NULL")
Item.includes(:purchase).where(purchases: { id: nil })
Технически первый пример работает без предложения "ссылки", но Rails 4 сбрасывает предупреждения об устаревании без него.
Ответ 3
Один интуитивный способ сделать это -
Item.all - Item.joins(:purchases)