Поиск записей без связанных записей в рельсах 3
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, которая возвращает людей, у которых нет домашних животных. Есть идеи? Я чувствую, что это очевидно, но это ускользает от меня в данный момент.
Ответы
Ответ 1
Попробуйте что-то вроде этого:
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()
передается строка.
Ответ 2
scope :without_pets, lambda { includes(:pets).where('pets.id' => nil) }
Ответ 3
Ответ Марк Уэстлинг правильный. Внешнее соединение - правильный путь. Внутреннее соединение (это то, что генерирует метод объединения, если вы передадите ему имя/символ ассоциации, а не собственный SQL) не будет работать, поскольку он не будет включать людей, у которых нет домашнего животного.
Здесь он написан как область действия:
scope :without_pets, joins("left outer join pets on pets.person_id = persons.id").where("pets.id is null")
(Если это не сработает, попробуйте заменить "people" на "people" - я не уверен, что такое имя вашей таблицы.)
Ответ 4
Вы должны использовать 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')
Ответ 5
Я не уверен, что ваша модель вашего любимца имеет идентификатор человека, но, возможно, эта попытка поможет вам как-то
scope :with_dog, joins(:pets).where("pets.type = 'Dog'")
scope :without_pets, joins(:pets).where("pets.person_id != persons.id")
Обновление: Исправлено имя метода запроса от "join" до "join".