Подтвердить что ты не робот

Поиск 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

4b9b3361

Ответ 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)