2012-05-05 3 views
0

Je souhaite obtenir des enregistrements Bar associés à un seul foo à travers les barres dans les modèles suivants, Foo <-> Bar <-> Baz.Comment utiliser ActiveRecord en association profonde

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 

mise en œuvre Naive:

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

Ce code génère une mauvaise requête, il exécute plusieurs fois. Ce que je veux est quelque chose comme ce qui suit:

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

, je veux aussi obtenir des objets comme ActiveRecord :: Relation afin que les requêtes SQL résultantes sont optimisées.

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 

Répondre

0

Vous devez définir les relations inverse aussi, une fois que vous avez fait que vous devriez être en mesure de faire quelque chose comme ceci:

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

Pour les requêtes complexes que je recommande aussi le squeel gem, il permet pour des requêtes plus compactes et prend également en charge les jointures externes.

Questions connexes