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

Поиск записей без связанных записей в рельсах 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, которая возвращает людей, у которых нет домашних животных. Есть идеи? Я чувствую, что это очевидно, но это ускользает от меня в данный момент.

4b9b3361

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