2012-08-29 12 views
18

レールがbefore_filterのようなフィルタを実装する方法に興味があります。レールはどのようにbefore_filterを実装していますか?

しかし、ソースコードを読んだ後、私はまだ混乱しています。

私は、レールのフレームワークがfilter_chainを維持しており、ターゲットメソッドの前にフィルタを実行していることに気付きました。

しかし、私は重要なプロセスを理解していません。レールはどのようにメソッド呼び出しをキャプチャしますか?

例えば、私はクラスDogを持っていて、メソッドバークにbefore_filterを設定しています。

dog.barkを呼び出すと、レールは何らかの方法でこの呼び出しを取得し、代わりにその変更されたメソッドを実行する必要があります。

しかし、ソースコードでこのようなコードは見つかりません。

誰でも私にそのアイデアを教えたり、コードがどこにあるのかを指摘できますか?あなたがbefore_filter、または任意の同様のフィルタafter_filteraround_filterと思う)を設定すると

答えて

20

、あなたはSymbolまたはProc、ラムダまたはブロックのいずれかでそうやっています。

before_filter :bark 
before_filter Proc.new { |k| k.bark } 

は、上記set_callbackを呼び出すことによって、スタックhereにシンボルまたはブロックを追加します。これはあなたが参照している 'チェーン'を構築します。

この 'チェーン'の各アイテムは、ActiveSupport::Callbacks::Callbackクラスのインスタンスです。このクラスは、

  • 方法(シンボル)を知っているか、それをブロックする(すなわち。あなたのクラスの:bark法)を実行する必要があり、それは内で実行しなければならない
  • コンテキスト(すなわち。あなたのDogクラス)

のインスタンスは、ActiveSupport::Callbacks::CallbackChainの中に__update_callbacksで追加されています。各Callbackクラスが初期化される

_compile_filterは、共通、呼び出し可能なフォーマットにSymbolProc、ラムダからフィルタを正規化し、または遮断するために実行されます。 CallbackChainが実行されるとき

最後に、フィルタが実際に適切なコンテキスト内で実行されるこの時点で各Callbackインスタンスにstart、及びそのを呼び出します。


それはあなたがないが、これはdog.barkを実行し、CallbackChainに追加するbefore_filterへの戻り値を渡すために起こっている

before_filter dog.bark 

のようなフィルタを作成することを指摘することが重要です。その目的は、後であなたのために実行するために、ある種の指示をbefore_filterに渡すことです。代わりに、

before_filter Proc.new { d = Dog.new; d.bark } 

のようなコードを実行します。Procのコードは実行されません。上記の行がRailsによって実行されるとき。代わりに、RailsはProcCallbackChainに渡すように言われています。 Procは、適切な時間に実行するためにRailsに渡す '命令'です。このためとして、樹皮

を、のは、あなたのDogクラスは単に

class Dog 
    def bark 

    end 

    def eat 

    end 
end 

(のように定義されたとしましょう:レールは、私が呼ばれている知っているどのように最初の場所で


これはひどい例ですが)のようなものがあります。

before_bark :eat 

これは、あなたがbarkコールバックを定義して、関連barkコールバックを実行するために、あなたのbark方法を教え必要です。

class Dog 
    extend ActiveModel::Callbacks 

    define_callbacks :bark 

    before_bark :eat 

    def bark 
    run_callbacks(:bark) { YOUR BARK CODE HERE } 
    end 

    def eat 

    end 
end 

ActiveRecord::Callbacksがこれを行う方法を確認できます。

これは実際にはeatbarkから直接呼び出すことができます(そして、そうする必要があります)が、実際には悪い例ですが、これでポイントを取得する必要があります。

+0

ありがとうございました!しかし、まだ混乱。あなたは「最後に、CallbackChainが実行されると...」と言っていました。私の質問は、CallbackChainを実行する必要があることをレールがどのようにして知っているのでしょうか?言ってやるがいい、before_filter:クラスDogに食べさせる。それから私がdog.barkを呼び出すとき、まず食べるべきです。しかし、どのように最初の場所では、レールは私が電話したことを知っていますか:樹皮? – HanXu

+0

答えを更新しました。 – deefour

+0

かなり明確ですが、まだ少し混乱しています。あなたの例では、バークを手動で再定義しますが、レールはコードによって自動的に行います。私はこれらのコードがどこにあるのかわかりません。 @haraldによると、レールは事前に各アクションを修正しています。私はAbstractController :: Baseで 'attr_internal'に気付きました。マジックが起こっていますか? – HanXu

1

Railsは、あなたが記述した方法でメソッド呼び出しを取得しません。 AbstractController::Base.processを見ると、ディスパッチされたアクションのために呼び出されるメソッドを検索し、フィルタを実行してから実際のメソッドを呼び出します。言い換えれば、コントローラメソッドは直接呼び出されるのではなく、このprocessメソッドによって呼び出されます。

+0

私はそれを得ました、レールは 'attr_internal'を使って各メソッドを新しく内部名に変更し、新しい名前ですべてのことを行うようですか? – HanXu

関連する問題