2015-05-19 108 views
1

我目前正在Rails模型中设置一个作用域以供ActiveAdmin使用。我想构建的范围应该会找到每个Job,它们过去都有survey_date,目前有Job.survey,并且没有Job.quotesRails ActiveRecord模型范围与has_many关联上的连接

这里是我的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 }) } 

我应该如何改变我的范围,使其正确地找到revelant Job记录?

+1

请注意'joins'将创建一个INNER JOIN,这意味着'quotes.id IS NULL'没有影响,并且这些作业永远不会显示try'includes(:surveys,:quotes).where(' survey_date <:current_time AND surveys.id IS NOT NULL AND quotes.id IS NULL',{current_time:Time.current})'这将创建2个LEFT OUTER JOIN,并且可能对您更好。关于关联加载以及这些方法如何工作,这是一篇很棒的[文章](http://blog.bigbinary.com/2013/07/01/preload-vs-eager-load-vs-joins-vs-includes.html) – engineersmnky

回答

3

您可以使用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 ids。

将它们拆分为两个单独的作用域:has_survey:without_quote可能更有意义,然后它们可以组合成一个方法。

def self.awaiting_quote 
    Job.has_survey.without_quote 
end 
+0

太好了,谢谢! – gosseti