3

Rails を使用したアジャイル Web 開発の本から

class Order < ActiveRecord::Base
   named_scope :last_n_days, lambda { |days| {:conditions =>
      ['updated < ?' , days] } }

   named_scope :checks, :conditions => {:pay_type => :check}
end

ステートメント

orders = Orders.checks.last_n_days(7)

データベースへのクエリは 1 つだけになります。

レールはこれをどのように実装しますか? 私はRubyが初めてで、これを可能にする特別な構造があるかどうか疑問に思っています。

そのようなメソッドを連鎖できるようにするには、named_scope によって生成された関数がそれ自体を返すか、さらにスコープを設定できるオブジェクトを返す必要があります。しかし、Ruby はこれが最後の関数呼び出しであり、今すぐデータベースにクエリを実行する必要があることをどうやって知るのでしょうか?

上記のステートメントは実際にデータベースにクエリを実行し、チェーンの結果として SQL ステートメントを返すだけではないため、これを尋ねます。

4

3 に答える 3

7

named_scope マジックには 2 つのトリック (必要に応じてパターン) が採用されています。

プロキシ パターン- クラスまたは関連付けで名前付きスコープ メソッドを呼び出すと、フィルタリングされた AR オブジェクトのコレクションではなく、常にActiveRecord::NamedScope::Scope クラスのインスタンスが返されます。このパターンは非常に便利ですが、プロキシ オブジェクトは本質的にあいまいであるため、物事がぼやけてしまうことがあります。

遅延読み込み- 遅延読み込み (このコンテキストでは、必要な場合にのみデータベースをヒットすることを意味します) のおかげで、スコープによって定義されたコレクションを操作する必要がある時点まで、名前付きスコープを連鎖させることができます。基になるコレクションを要求するたびに、チェーンされたすべてのスコープが評価され、データベース クエリが実行されます。

最後に 1 つ: IRB で名前付きスコープ (またはある種の委譲を使用するもの) を操作する際に留意すべきことが 1 つあります。Enter を押すたびに、事前に書いたものが評価さinspectれ、返された値に対してメソッドが呼び出されます。チェーンされた名前付きスコープの場合、式全体が Scope インスタンスに評価されますが、IRB がそのinspectメソッドを呼び出すと、スコープが評価され、データベース クエリが起動されます。これは、inspectメソッドが、基になるコレクションまでのすべてのスコープ オブジェクトを介して伝達される委譲によって行われるという事実によって発生します。

于 2010-04-09T19:29:00.463 に答える
3

あなたはこれを試してみたいかもしれません

class Order < ActiveRecord::Base

  class << self
    def last_n_days(n)
      scoped(:conditions => ['updated < ?', days])
    end
    def checks
      scoped(:conditions => {:pay_type => :check})
    end
  end

end

使い方は同じです

@orders = Order.last_n_days(5)
@orders = Order.checks
@orders = Order.checks.last_n_days(5)

これでも、お気に入りの遅延読み込みはすべて実行されます。つまり、レコードにアクセスしようとするまで、クエリは作成されません。おまけ: Rails3対応!

名前付きスコープは死んでいる

于 2010-04-10T05:47:57.177 に答える
0

とてもかっこいい。私はJavascriptでこのようなことをすることを考えていましたが、Javascriptはかなり奇妙な動作をします.

ステートメント:

var x = SomeObject;

SomeObject の toString() 関数を呼び出しません。しかし、声明:

var x;
x = SomeObject;

期待どおりに toString() 関数を正しく呼び出します。

これにより、Javascript がチェーンを使ってクールなことを行うのを防ぎます。=(

于 2010-04-09T14:02:14.680 に答える