2012-03-01 11 views
5

私はあなたのためにそれを視覚化させてください。ActiveRecordはチェーン内の最後のメソッド呼び出しをどのように検出しますか?

class Product < ActiveRecord::Base 
end 

Product.first.title 
#=> "My sample product" 

ここには特別なものはありません。単純なメソッド呼び出しです。次に、次の例を見てみましょう。

class Product < ActiveRecord::Base 
    def method_missing 
    end 
end 

Product.first.title 
#=> nil 

Product.first 
Product.first.title 
#=> "My sample product" 

これはどのように可能ですか?何らかの方法で彼らはメソッドチェーンの終わりを決め、それに基づいて行動しますか?少なくともそれは私の理論です。

誰でもこの動作を説明できますか?

答えて

7

irbを使用して物事を調査するというアーティファクトが表示されています。

あなたはこの言うとき:

> Product.first.title 
#=> nil 

をごmethod_missingがレイジーロードtitleメソッドに呼び出され、あなたがnilを取得します。

あなたが言うときは、この:あなたはこれを効果的にやっている

> Product.first 

:最初の製品のインスタンスがロードされ、その後、irbそれにinspectを呼び出すとARが追加されます

> p = Product.first; puts p.inspect 

途中のアクセサメソッド。その結果、Productにはtitleメソッドが追加されます。したがって、これを行う:Product.first.titleを呼び出すための本当のtitle方法があるだろうと

> Product.first 
> Product.first.title 

は、すべてあなたのmethod_missingを呼び出すことはありません。

あなたはこのように再度お試し場合:

> Product.first; nil 
> Product.first.title 

次の2つのnil秒が表示されます。


限りの連鎖が行くように、ActiveRecordのは本当に終わりを検出しない、それはいくつかの方法が自然に、データベースから実際のデータを必要とし、いくつかにはない呼び出すだけということです。

あなたがwhereorder、または他の照会メソッドを呼び出す場合は、バックActiveRecord::Relationインスタンスを取得し、あなたはその関係オブジェクトのチェーンよりクエリメソッドとスコープをすることができます。例えば、(ActiveRecordのは::関係はActiveRecord::QueryMethodsを含むことにより取得)、このようになりますwhere:それはちょうど、現在のクエリのコピーを作成コピーにいくつかのことを追加し、あなたのコピーを与える

def where(opts, *rest) 
    return self if opts.blank? 

    relation = clone 
    relation.where_values += build_where(opts, rest) 
    relation 
end 

バック。

あなたがfirstlastto_aallEnumerable方法(すなわち、あなたがeachを呼び出す)のいずれかを呼び出す場合、...特定のインスタンスについて質問すると、問題のモデルインスタンスを実現するためにActiveRecordがクエリを実行する必要があります。例えば、ActiveRecord::Relation#to_aは次のようになります。

def to_a 
    logging_query_plan do 
    exec_queries 
    end 
end 

allto_aのラッパーより少しです。

ActiveRecordは実際にはチェーンの終わりがわからないので、データベースから何もロードされないので、チェーンが終了する場所を教えてください。と言って

+0

私はチェーンの終わりを検出すると思います。ファインダのプロキシオブジェクトを返さない場所です! – phoet

+0

これは質問に関するものではありません。なぜなら、 '' '' method_missing'''がモデルの中で使われるとき、 '' '' Product.first.title'''は '' '' Product.first'''が呼ばれるまで '' '' nil''を返すのです。 '' '' Product.first''を呼ぶと、titleは '' 'My sample blog''を返します。 – user544941

+0

@ user544941:ああ、私は彼が何を求めているのかを見ています:何が彼の 'method_missing'を置き換えるかバイパスしています。 –

関連する問題