2013-04-20 50 views
1

首先,我是一個Ruby/Rails新手,所以我很抱歉如果這個問題是基本的。創建一個連接到子查詢的Rails 3作用域

我有一個DB是(除其他事項外)看起來是這樣的:

organizations { id, name, current_survey_id } 
surveys { id, organization_id } 
responses { id, survey_id, question_response_integer } 

我試圖創建將當前的調查回答的平均值的範圍方法傳入組織關係。換句話說,這是獲取傳遞給方法的範圍將生成SQL,看起來像更多或更少的這樣的:

select * from organizations 

而且我喜歡這個範圍時,它會通過我的拉姆達處理後,以生成SQL,看起來像這樣:

select o.id, o.name, cs.average_responses 
from organizations o join 
(select r.id, avg(r.question_response_integer) as average_responses 
    from responses r 
    group by r.id) cs on cs.id = o.current_survey_id 

我已經得到了最好是這樣的:

current_survey_average: lambda do |scope, sort_direction| 
    average_answers = Responses. 
    select("survey_id, avg(question_response_integer) as average_responses"). 
    group("survey_id") 
    scope.joins(average_answers).order("average_responses #{sort_direction}") 
end 

這大多隻是在黑暗中刺 - 除其他事項外,它沒有指定範圍如何可以被表達被加入到average_answers - 但我一直沒有找到任何關於如何進行這種連接的文檔,而且我正在耗盡所有的東西來嘗試。

有什麼建議嗎?

編輯:感謝肖恩山的答案。只需把它記錄在案,這裏是我結束了持續代碼:

current_survey_average: lambda do |scope, sort_direction| 
    scope_table = scope.arel.froms.first.name 
    query = <<-QUERY 
    inner join (
    select r.survey_id, avg(r.question_response_integer) as average_responses 
     from responses r 
     group by r.survey_id 
    ) cs 
    on cs.survey_id = #{scope_table}.current_survey_id 
    QUERY 
    scope. 
    joins(query). 
    order("cs.average_responses #{sort_direction}") 
end 

這就是說,我可以看到直接把averaged_answers範圍在responses類的利益 - 所以我最終可能這樣做。

回答

1

我還沒有能夠測試這個,但我認爲下面的工作,無論是原樣或稍微調整。

class Response < ActiveRecord::Base 
    scope :averaged, -> { select('r.id, avg(r.question_response_integer) as average_responses').group('r.id') } 

    scope :current_survey_average, ->(incoming_scope, sort_direction) do 
    scope_table = incoming_scope.arel.froms.first.name 
    query = <<-QUERY 
     INNER JOIN (#{Arel.sql(averaged.to_sql)}) cs 
     ON cs.id = #{scope_table}.current_survey_id 
    QUERY 

    incoming_scope.joins(query).order("average_responses #{sort_direction}") 
    end 
end 

所以我在這裏所做的是我已經將內部查詢拆分到另一個稱爲平均值的範圍。由於您不知道current_survey_average中的傳入範圍來自哪個表,我通過scope.arel.froms.first.name獲得了範圍表名稱。然後我創建了一個查詢字符串,它使用averaged作用域並使用scope_table變量將其加入。其餘的都是不言自明的。

如果確實知道傳入範圍將始終來自組織表,那麼您不需要額外的scope_table變量。您可以將其硬編碼到連接查詢字符串中。

我會提出一個建議。如果您無法控制sort_direction,那麼我不會將其直接輸入到訂單字符串中。

+1

非常感謝,那就是答案。我上面發佈了我的修改版本:非常感謝。 – 2013-04-22 04:06:05