21

レールが のようなフィルターを実装する方法に興味がありますbefore_filter

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

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

しかし、重要なプロセスがわかりません。Rails はメソッド呼び出しをどのようにキャプチャしますか?

たとえば、 classがあり、 aをメソッド bark にDog設定します。before_filter

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

ただし、ソース コードにはそのようなコードは見つかりません。

誰かアイデアを教えてくれたり、コードの場所を指摘してくれませんか?

4

2 に答える 2

22

When you set a before_filter, or any similar filter (think after_filter, around_filter), you're doing so with either a Symbol or a Proc, lambda or block.

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

The above appends the symbols or blocks to a stack here, by calling set_callback. This builds the 'chain' you're referring to.

Each item in this 'chain' is an instance of the ActiveSupport::Callbacks::Callback class. This class knows

  • The the method (Symbol) or block it must run (ie. your class' :bark method)
  • The context which it must run within (ie. your Dog class)

The Callback instances are appended to a ActiveSupport::Callbacks::CallbackChain in __update_callbacks.

When each Callback class is initialized, _compile_filter is run to normalize the filter from the Symbol, Proc, lambda, or block into a common, callable format.

Finally, when the CallbackChain is run, it will call start on each Callback instance, and its at this point that the filter is actually executed within the proper context.


It's important to point out that you would not create a filter like

before_filter dog.bark

this is going to execute dog.bark and pass it's return value to before_filter to be appended to the CallbackChain. The intention is to pass some sort of instruction on to before_filter for Rails to later execute for you. You would instead do something like

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

The code within the Proc is not executed. when the line above is run by Rails. Instead, Rails is being told to pass the Proc to the CallbackChain. The Proc is the 'instruction' you're passing on to Rails to execute at the appropriate time.


how in the first place does rails know I have called :bark

As for this, let's say your Dog class is simply defined as

class Dog
  def bark

  end

  def eat

  end
end

(Though this is a terrible example), you might want to have something like

before_bark :eat

This requires you define the bark callback, and then tell your bark method to run the related bark callbacks.

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

You can see how ActiveRecord::Callbacks does this.

This really is a bad example though because you can (and should) just call eat directly from bark, but this should get the point across.

于 2012-08-29T11:08:03.223 に答える
1

Rails は、説明した方法でメソッド呼び出しをキャプチャしません。見るAbstractController::Base.processと、ディスパッチされたアクションに対して呼び出されるメソッドが検索され、フィルターが実行されてから、実際のメソッドが呼び出されます。つまり、コントローラ メソッドは直接呼び出されるのではなく、このprocessメソッドを通じて呼び出されます。

于 2012-08-29T11:15:25.653 に答える