2016-02-15 3 views
1

У меня есть родительский класс Job, который может иметь от 0 до многих LaserSheets:Rails: список всех родительских объектов, чьи дети имеют ненулевое значение

class Job < ActiveRecord::Base 
    has_many :laser_sheets 
    ... 
end 

class LaserSheet < ActiveRecord::Base 
    belongs_to :job 
    ... 
end 

В настоящее время index действия в контроллере Job возвращает все Jobs с 1 или более LaserSheets:

class JobsController < ApplicationController 
    ... 
    def index 
    @jobs = Job.joins(:laser_sheets).uniq.all.order(sort_column + " " + sort_direction) 
    end 
    ... 
end 

LaserSheet имеет атрибут DATETIME cut_at. Я хотел бы иметь возможность фильтровать результаты Job, чтобы показать только Jobs, где все LaserSheets имеют ненулевые cut_at атрибуты.

Я нашел an answer, объясняя, как фильтровать детей на основе атрибута родителя, но я не смог понять, как это сделать в обратном порядке.

Редактировать 2/17/16:

рекомендация

Per Хьеу, я попытался следующие:

@jobs = Job.joins(:laser_sheets).where('laser_sheets.id NOT IN (SELECT id 
                   FROM laser_sheets 
                   WHERE cut_at IS NULL)') 

Он не явился на работу, поэтому я высевают пустую базу данных со следующими тест информация:

Job.create!(id: 1, name: "Job 1") 
Job.create!(id: 2, name: "Job 2") 
Job.create!(id: 3, name: "Job 3") 
LaserSheet.create!(id: 1, name: "1", job_id: 1, cut_at: nil) 
LaserSheet.create!(id: 2, name: "2", job_id: 1, cut_at: nil) 
LaserSheet.create!(id: 3, name: "3", job_id: 2, cut_at: nil) 
LaserSheet.create!(id: 4, name: "4", job_id: 2, cut_at: "2016-02-17 23:00:00") 
LaserSheet.create!(id: 5, name: "5", job_id: 3, cut_at: "2016-02-17 23:00:00") 
LaserSheet.create!(id: 6, name: "6", job_id: 3, cut_at: "2016-02-17 23:00:00") 

правильный ответ на мой вопрос должен возвращать только Job 3, так как это единственный Job со всеми LaserSheets с не-NULL cut_at. Я побежал предложенный ответ Хьеу в:

jobs = Job.joins(:laser_sheets).where('laser_sheets.id NOT IN (SELECT id FROM laser_sheets WHERE cut_at IS NULL)') 

    Job Load (0.5ms) SELECT "jobs".* FROM "jobs" INNER JOIN "laser_sheets" ON "laser_sheets"."job_id" = "jobs"."id" WHERE (laser_sheets.id NOT IN (SELECT id FROM laser_sheets WHERE cut_at IS NULL)) 

и возвращает как Job 2 и Job 3, которые не то, что я ищу.

Редактировать 2/19/16: добавил cut_at информацию, чтобы проверить случай

ответ

0

Это объединяет laser_sheets в рабочие места, но только там, где нет необрезанных лазеров.

Job.joins(:laser_sheets). 
    where('not exists (select * from laser_sheets as l2 where l2.job_id = jobs.id and l2.cut_at is null)') 

Запуск от набора данных возвращается только грести 3

+0

Это работает, спасибо! – Ryan

0

где все LaserSheets имеют ненулевым cut_at атрибуты

Логически, она равна: ALL (LaseerSheet's cut_at IS NOT NULL) = NOT (ANY (LaseerSheet's cut_at IS NULL))

Таким образом, запрос будет:

@jobs = Job.joins(:laser_sheets).where('laser_sheets.id NOT IN (SELECT id 
                    FROM laser_sheets 
                    WHERE cut_at IS NULL)') 
+0

Это, как представляется, вернуться Работа с ** ** по крайней мере один LaserSheet с ненулевым cut_at. Я пытаюсь найти вакансии, где ** каждый ** LaserSheet имеет ненулевой cut_at. – Ryan

+0

@Ryan: Позвольте снова проверить запрос, я использовал 'NOT IN', а не' IN', поэтому логика абсолютно правильная –

+0

Я редактировал свой первоначальный вопрос, чтобы включить тесты, показывающие, почему это не работает. – Ryan

Смежные вопросы