2011-02-08 7 views
4

ジョインを指定する複数のステートメントを持つようなクエリを作成しようとすると、それぞれにメッセージがチェーンされます。クエリが実行されると、すべての結合が取得されますが、最初の呼び出しの場所のみが取得されます。ここでは、クエリやっている方法のボディです:複数のジョインをレールで連鎖させる

observations_joins = Observation.joins(:obs_session => :project).where(:obs_sessions=>{:project_id=>self.project.id}) 
descriptor_hash = descriptor_where_hash if tag_descriptors && tag_descriptors.size > 0 
puts "The descriptor_hash: #{descriptor_hash}" 
observations = observations_joins.joins(:obs_descriptors).where("#{descriptor_hash['query_string']}", descriptor_hash['match_values']) if tag_descriptors && tag_descriptors.size > 0 
arel = observations.arel 
puts "The arel sql should be: #{arel.to_sql}" 
observations 

はI第二の内側から呼び出される別の方法が声明に参加し、その潜在的な試合値を反復処理し、文字列と使用する値を生成し、持っています。ここで、本体:

match_values = [] 
query_string = "obs_descriptors.tag_name = ?" 
tag_descriptors.each_index do |index| 
    query_string = query_string + " #{tag_descriptors.fetch(index).qualifier_key} obs_descriptors.tag_name = ?" if index != 0 
    match_values << tag_descriptors.fetch(index).tag_name 
end 
{:match_values=>match_values, :query_string=>query_string} 

ように、SQLが生成され得るようなルックス:

SELECT  `observations`.* FROM  `observations` INNER JOIN `obs_sessions` ON `obs_sessions`.`id` = `observations`.`obs_session_id` INNER JOIN `projects` ON `projects`.`id` = `obs_sessions`.`project_id` INNER JOIN `obs_descriptors` ON `obs_descriptors`.`observation_id` = `observations`.`id` WHERE  (`obs_sessions`.`project_id` = 1) 

と場所の条件の第2のセットを含んでいません。私はハッシュを印刷して、私の心が失われていないことを確認し、そこに価値があることを確かめるために、実際にそこにある。

私はこれを期待しているようにこれを行うために何が欠けていますか?

答えて

5

ここに自分の質問に答える。私がこの作業を得るために見つけた最もエレガントで簡潔な方法は、直接arelに落とすことでした。また、元のコードにいくつかの問題がありましたが、まだグループ化された条件を得るためにarelを使用する必要がありました。コンテキストに関しては、関連するデータに基づいて、セミの高度なクエリを動的に作成する必要があるオブジェクトがあるため、関連するデータが存在するかどうかを確認したい場合や、追加の結合とwheres。

def find_observations 
    observations = Observation.select('distinct observations.*').includes(:obs_session).includes(:judgements).includes(:concepts).includes(:obs_descriptors) 
    observations = observations.joins(:obs_session => :project).where(:obs_sessions=>{:project_id=>self.project.id}) 
    if tag_descriptors && tag_descriptors.size > 0 
    observations = observations.where(descriptor_predicate) 
    end 
    if session_descriptors && session_descriptors.size > 0 
    observations = observations.where(session_predicate) 
    end 
    if user_descriptors && user_descriptors.size > 0 
    observations = observations.where(user_predicate) 
    end 
    #puts "observations sql is: #{observations.to_sql}" 
    observations.all 
end 

上記の方法は、任意にARオブジェクトを連鎖するとき、最終的なクエリを構築しながら、ここで使用されるAREL呼び出し戻り、残りのメソッドを呼び出して:ここで、関連する方法の最終バージョンです。不本意に気づく。私はarelを使ってこのバージョンを作っていましたが、それは動作していたようですが、実際には重複を返していました。私はグループ(some_attribute)を使って物を偽造することに言及していましたが、それはチェーンの問題を引き起こすことが判明しました。だから、私はActiveRelationを使って、別々の、結合とインクルードを指定し、残りの部分はarelに指定しました。

次は、もともと私に多くのトラブルを与えていた部分でした。可能な可変数があり、それぞれがAND条件またはOR条件のいずれかであり、生成されたwhere節の残りの部分を混乱させないように、別々にグループ化する必要があります。

def descriptor_predicate 
    od = Arel::Table.new :obs_descriptors 
    predicate = nil 
    self.tag_descriptors.each_index do |index| 
    descriptor = self.tag_descriptors.fetch(index) 
    qual_key = descriptor.qualifier_key 
    tag_name = descriptor.tag_name 
    if index == 0 
     predicate = od[:descriptor].eq(tag_name) 
    else 
     if qual_key == "OR" 
     predicate = predicate.or(od[:descriptor].eq(tag_name)) 
     else 
     predicate = predicate.and(od[:descriptor].eq(tag_name)) 
     end 
    end 
    end 
    predicate 
end 

および潜在するため、最終的に他の述語の方法は、エンティティ値を参加:

def session_predicate 
    o = Arel::Table.new :observations 
    predicate = nil 
    self.session_descriptors.each_index do |index| 
    obs = self.session_descriptors.fetch(index) 
    if index == 0 
     predicate = o[:obs_session_id].eq(obs.entity_id) 
    else 
     predicate = predicate.or(o[:obs_session_id].eq(obs.entity_id)) 
    end 
    end 
    predicate 
end 

def user_predicate 
    o = Arel::Table.new :observations 
    predicate = nil 
    self.user_descriptors.each_index do |index| 
    obs = self.user_descriptors.fetch(index) 
    if index == 0 
     predicate = o[:contributor_id].eq(obs.entity_id) 
    else 
     predicate = predicate.or(o[:contributor_id].eq(obs.entity_id)) 
    end 
    end 
    predicate 
end 

def descriptor_where_string(included_where_statements) 
    tag_descriptors.each_index do |index| 
    qual_key = tag_descriptors.fetch(index).qualifier_key 
    tag_name = tag_descriptors.fetch(index).tag_name 
    if index == 0 
     query_string = "obs_descriptors.descriptor = #{tag_name}" 
    else 
     if qual_key == "OR" 
     query_string = query_string + " #{qual_key} obs_descriptors.descriptor = #{tag_name} AND #{included_where_statements} " 
     else 
     query_string = query_string + " #{qual_key} obs_descriptors.descriptor = ?" 
     end 
    end 
    end 
    query_string 
end 

は、最終的に、私は最善の解決策は、明確を提供するための連鎖と含み、直接ARELを用いActiveRelation両方を活用関与見出さ関連する値の条件については、これが誰かをある時点で助けてくれることを願っています。

関連する問題