Поиск записей без связанных записей в рельсах 3 - PullRequest
13 голосов
/ 17 марта 2011
class Person < ActiveRecord::Base
  has_many :pets

  scope :with_dog, join(:pets).where("pets.type = 'Dog'")
  scope :without_pets ???????????????????????????????????
end

class Pet < ActiveRecord::Base
  belongs_to :people
end

Я бы хотел добавить в модель Person область, которая возвращает людей, у которых нет домашних животных. Есть идеи? Я чувствую, что это очевидно, но на данный момент это ускользает от меня.

Ответы [ 5 ]

22 голосов
/ 06 мая 2011
scope :without_pets, lambda { includes(:pets).where('pets.id' => nil) }
9 голосов
/ 17 марта 2011

Попробуйте что-то вроде этого:

Person.joins('left outer join pets on persons.id=pets.person_id').
       select('persons.*,pets.id').
       where('pets.id is null')

Я не проверял это, но оно должно работать.

Идея состоит в том, что мы выполняем внешнее левое соединение, поэтомуполя домашних животных будут нулевыми для каждого человека, у которого нет домашних животных.Возможно, вам потребуется включить :readonly => false в объединение, поскольку ActiveRecord возвращает объекты только для чтения, когда join() передается строка.

5 голосов
/ 17 марта 2011

Марк Вестлинг ответил правильно.Внешнее соединение - верный путь.Внутреннее объединение (которое генерирует метод joins, если вы передадите ему имя / символ ассоциации, а не свой собственный SQL), не будет работать, поскольку в него не войдут люди, у которых нет питомца.* Здесь это написано как область действия:

scope :without_pets, joins("left outer join pets on pets.person_id = persons.id").where("pets.id is null")

(Если это не сработает, попробуйте заменить «персон» на «люди» - я не уверен, как называется ваша таблица)1006 *

1 голос
/ 20 мая 2014

Вы должны использовать LEFT OUTER JOIN, чтобы найти записи без связанных записей. Вот адаптированная версия кода, который я использую:

scope :without_pets, joins('LEFT OUTER JOIN pets ON people.id = pets.person_id').group('people.id').having('count(pets.id) = 0')
0 голосов
/ 17 марта 2011

Я не уверен, что у вашей модели питомца есть личный идентификатор, но, возможно, эта попытка вам как-то поможет

scope :with_dog, joins(:pets).where("pets.type = 'Dog'")
scope :without_pets, joins(:pets).where("pets.person_id != persons.id")

Обновление: исправлено имя метода запроса от 'join' до 'joins'.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...