Краще:
Person.includes(:friends).where( :friends => { :person_id => nil } )
Для hmt це в основному те саме, ви покладаєтесь на те, що людина, яка не має друзів, також не матиме контактів:
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
Хтось запитав про зворотне, друзів, у яких немає людей. Як я коментував нижче, це насправді дало мені зрозуміти, що останнє поле (вище: the :person_id
) насправді не повинно бути пов’язане з моделлю, яку ви повертаєтесь, воно просто повинно бути полем в таблиці приєднання. Вони все будуть, nil
щоб це було будь-яким із них. Це призводить до більш простого рішення вищезазначеного:
Person.includes(:contacts).where( :contacts => { :id => nil } )
А потім переключити це на повернення друзів без людей стає ще простіше, ви змінюєте лише клас спереду:
Friend.includes(:contacts).where( :contacts => { :id => nil } )
Оновлення 3 - рейки 5
Завдяки @Anson за відмінне рішення Rails 5 (дайте йому декілька +1 для його відповіді нижче), ви можете використовувати, left_outer_joins
щоб не завантажувати асоціацію:
Person.left_outer_joins(:contacts).where( contacts: { id: nil } )
Я включив його сюди, щоб люди знайшли його, але він заслуговує +1 для цього. Чудове доповнення!
Оновлення 4 - Рейки 6.1
Дякуємо Тім Парку , що вказали, що в майбутньому 6.1 ви можете це зробити:
Person.where.missing(:contacts)
Завдяки публікації, з якою він також посилався.