2012-05-05 1 views
0

以下のモデルでは、単一のfooに関連付けられたバーレコードを取得したいと考えています。 Foo <-> Bar <-> BazディープアソシエーションでのActiveRecordの使い方

class Foo < ActiveRecord::Base 
    has_many :foo_bar_assocs 
    has_many :bars, through: :foo_bar_assocs 
end 

class Bar < ActiveRecord::Base 
    has_many :bar_baz_assocs 
    has_many :bazs, through: :bar_baz_assocs 
    attr_readonly :name 
end 

class Baz < ActiveRecord::Base 
end 

class FooBarAssoc < ActiveRecord::Base 
    belongs_to :foo 
    belongs_to :bar 
end 

class BarBazAssoc < ActiveRecord::Base 
    belongs_to :bar 
    belongs_to :baz 
end 

ナイーブな実装:

foo = Foo.find(id) 
baz_of_foo = foo.bars.where(name: params[:name]).map{|b| b.bazs}.flatten.uniq 

このコードは悪いクエリを生成し、それが何度も実行されます。

baz_of_foo = foo.something_good_query(bar_name: params[:name]) 

はまた、私は結果のSQLクエリが最適化されるように、ActiveRecordの::関係のようなオブジェクトを取得したい: は、私が欲しいのは、次のようなものです。

baz_of_foo.each{ ... } # SELECT DISTINCT baz.* FROM ... 
baz_of_foo.count  # SELECT COUNT(DISTINCT baz.*) FROM ... 
baz_of_foo.exists?  # SELECT baz.* FROM ... TAKE 1 

答えて

0

あなたはこのような何かを行うことができる必要があることをやった後、あなたは、あまりにも逆の関係を定義する必要があります複雑なクエリの場合

Baz.joins(:bar => :foo).where(:bar => {:name => params[:name], :foo => {:id => foo_id}}) 

を私はまた、それが可能に、squeel gemをお勧めしますよりコンパクトなクエリ用であり、外部結合もサポートしています。