Лучше:
Person.includes(:friends).where( :friends => { :person_id => nil } )
Для хмт это в основном то же самое, вы полагаетесь на то, что у человека без друзей также не будет контактов:
Person.includes(:contacts).where( :contacts => { :person_id => nil } )
Обновление
У вас есть вопрос о has_one
в комментариях, так что просто обновление.Хитрость в том, что includes()
ожидает имя ассоциации, а where
ожидает имя таблицы.Для has_one
ассоциация обычно выражается в единственном числе, так что она меняется, но часть where()
остается такой, как есть.Так что, если Person
только has_one :contact
, то ваше утверждение будет следующим:
Person.includes(:contact).where( :contacts => { :person_id => nil } )
Обновление 2
Кто-то спросил об обратном, друзья без людей.Как я прокомментировал ниже, это фактически заставило меня понять, что последнее поле (выше: :person_id
) на самом деле не обязательно должно быть связано с возвращаемой моделью, оно просто должно быть полем в таблице соединений.Они все будут nil
, так что это может быть любой из них.Это приводит к более простому решению вышеперечисленного:
Person.includes(:contacts).where( :contacts => { :id => nil } )
И затем переключение на возвращение друзей без людей становится еще проще, вы меняете только класс впереди:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
Обновление 3 - Rails 5
Благодаря @Anson за отличное решение для Rails 5 (дайте ему + 1с за ответ ниже), вы можете использовать left_outer_joins
, чтобы избежать загрузки ассоциации:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
Я включил его сюда, чтобы люди его нашли, но он заслуживает +1 за это.Отличное дополнение!