2011-02-10 10 views
0

私は仕事でこの奇妙な問題に遭遇しました。問題を浮き彫りにするために最小限のアプリケーションを作成しました。私はアソシエーションの後に名前付きスコープが続くと、重複するSQLクエリ

p = Parent.first 
p.children.only_adults.all() 

を行うときに今、私はレールがすべての条件を含む単一のSQLクエリを生成するために期待される

class Parent < ActiveRecord::Base 
    has_many :children 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 
    named_scope :only_adults, :conditions => "adult is true" 
end 

:私は、単純な関連を持つ2つのモデルがあります。しかし、ここで私は、ログで見るものです:

Child Load (0.5ms) SELECT * FROM "children" WHERE ("children".parent_id = 1) 
Child Load (0.3ms) SELECT * FROM "children" WHERE ("children".parent_id = 1) AND ((adult is true) AND ("children".parent_id = 1)) 

最初のクエリは、基本的には役に立たないと大規模なコレクションの場合には非常に時間がcomsumingすることができます。

誰かがレールがそのように動作している理由を知っている人はいますか?私はby_parentが名前付き範囲である

Child.by_parent(p.id).only_adults.all() 

を行う代わりに、

p.children.only_adults.all() 

を行う

注、私は一つだけのクエリを取得します。

parent_id条件の重複にも注意してください。これは大きな問題ではありません。

フィードバックいただきありがとうございます。

答えて

3

理由は、Rails 3.0.xではなく、Rails 2.3.xでクエリを実行する方法と関係があります。 Rails 2では、p.childrenを呼び出すと、残りのクエリに付けられた名前付きスコープに関係なく、自動的にクエリが実行されます。これを回避する唯一の方法は、 "Child.by_parent(p.id).only_adults.all()"のようにnamed_scopesを組み合わせて使用​​することです。名前付きスコープはクエリの延期動作を保持するためです。 Rails 3では、executeキーワード(count、all、first、last)が見つかるまでクエリが構築されるので、1つのクエリで次のようにすることができます:

class Child < ActiveRecord::Base 
    belongs_to :parent 
    scope :only_adults, where(adult: true) 
end 

Parent.first.children.only_adults.all() 

# SELECT * FROM "children" WHERE ("children".parent_id = 1) AND (adult is true) 
+0

ありがとう! –

関連する問題