Rails ActiveRecord模型范围,具有has_many关联的连接

时间:2015-05-19 15:50:50

标签: ruby-on-rails ruby activerecord model active-record-query

我目前正在我的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记录?

2 个答案:

答案 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') }