我目前正在我的Rails模型中设置一个范围供ActiveAdmin使用。我想要构建的范围应该找到过去有Job
的每个survey_date
,其中Job.survey
存在,而Job.quotes
不存在。
以下是我Job
模型的缩写版本:
has_many :quotes
has_many :surveys
scope :awaiting_quote, lambda { joins(:surveys, :quotes).where('survey_date < :current_time AND surveys.id IS NOT NULL AND quotes.id IS NULL', { current_time: Time.current }) }
我应该如何更改我的范围,以便正确找到重要的Job
记录?
答案 0 :(得分:4)
Rails 5的更新
正如mad_raz提到的,在Rails 5.0+中,您可以使用left_outer_joins
:
scope :awaiting_quote, -> { joins(:surveys).
left_outer_joins(:quotes).
where('survey_date < :current_time', { current_time: Time.current }).
where('quotes.id IS NULL')
}
但是,您仍必须提供where('quotes.id IS NULL')
检查才能返回尚未收到报价的记录。有关外连接的可视化表示,请参见https://stackoverflow.com/a/16598900/1951290。
将这些分成两个独立的范围仍然是最有意义的。
Rails 4
您可以使用joins
创建左外连接,只需要更明确一些。
scope :awaiting_quote, -> { joins(:surveys).
joins('LEFT OUTER JOIN quotes ON quotes.job_id = jobs.id').
where('survey_date < :current_time', { current_time: Time.current }).
where('quotes.id IS NULL')
}
您不需要surveys.id IS NOT NULL
,因为成功的内部联接不会包含nil ID。
将它们分成两个独立的范围:has_survey
和:without_quote
可能更有意义,然后可以将它们合并到一个方法中。
def self.awaiting_quote
Job.has_survey.without_quote
end
答案 1 :(得分:1)
Rails 5引入了可以使用的left_outer_joins
方法
scope :awaiting_quote, -> { joins(:surveys).left_outer_joins(:quotes).where('yada yada') }