Rails 4 позволяет найти родителей без детей

Я нашел один ответ, в котором можно было найти примеры для поиска родителей с n детьми, но то же самое нельзя использовать для поиска родителей без детей (предположительно, поскольку их исключение исключает).

 scope :with_children, joins(:children).group("child_join_table.parent_id").having("count(child_join_table.parent_id) > 0") 

Может кто-то указать мне верное направление?

3 Solutions collect form web for “Rails 4 позволяет найти родителей без детей”

Это должно выполнить требуемую работу:

Рельсы 3 и 4

 scope :without_children, includes(:children).where(:children => { :id => nil }) 

Большая разница здесь состоит в том, что joins входящие в includes include: include include все отношения, если они существуют, соединение будет загружать только связанные объекты и игнорировать объект без отношения.

На самом деле, scope :with_children, joins(:children) должно быть достаточно, чтобы вернуть родителя как минимум с одним ребенком. Попробуйте!

Рельсы 5

См. Ответ @ Anson ниже


Как отметил @MauroDias, если это самореферентная связь между вашим родителем и детьми, этот код выше не будет работать.

С небольшим количеством исследований я узнал, как это сделать:

Рассмотрим эту модель:

 class Item < ActiveRecord::Base has_many :children, :class_name => 'Item', :foreign_key => 'parent_id' 

Как вернуть все предметы без детей (ren):

 Item.includes(:children).where(children_items: { id: nil }) 

Как я нашел таблицу children_items ?

Item.joins(:children) генерирует следующий SQL:

 SELECT "items".* FROM "items" INNER JOIN "items" "children_items" ON "children_items"."parent_id" = "items"."id" 

Поэтому я догадался, что Rails использует таблицу, когда ей нужен JOIN в самореферентном случае.


Похожие вопросы:

  • Как запросить модель на основе атрибута другой модели, которая относится к первой модели?
  • Rails активная запись запросов к ассоциации с ‘существует’
  • Rails 3, has_one / has_many с условием lambda
  • Объединение нескольких таблиц с активными записями

@MrYoshiji имеет надежный ответ Rails 4, но для людей, приезжающих сюда с Rails 5, у вас есть больше возможностей.

Использование Rails 5:

С Rails 5 вы также можете использовать left_outer_joins, чтобы избежать загрузки ассоциации. Он был введен в запрос тяги № 12071 .

 scope :without_children, left_outer_joins(:children).where(children: { id: nil }) 

Для родителей с детьми решение Rails 4 г-на Йошиджи все еще используется:

 scope :with_children, joins(:children) 

Вот как я решил это для Rails 5:

 scope :without_comments, -> do left_outer_joins(:comments).where(comments: { id: nil }) end 
  • Рельсы: не удалось найти рейды
  • Запрос ActiveRecord OR
  • ActiveModel :: ForbiddenAttributesError при создании нового пользователя
  • Рельсы, расширяющие ActiveRecord :: Base
  • Rails 2: Model.find (1) дает ошибку ActiveRecord, когда id 1 не существует
  • Как проверить заголовок страницы с Capybara 2.0?
  • Как пропустить обратные вызовы ActiveRecord?
  • Как отключить протоколирование сообщений конвейера (звездочки) в Rails 3.1?
  • Как вы справляетесь со вспышкой Rail с запросами Ajax?
  • Rails - Nested включает в Active Records?
  • Почему `config.time_zone`, кажется, ничего не делает?
  • Давайте будем гением компьютера.