0

Ruby on Rails 2.3.2 でフィルタ チェーンを操作するより動的な方法が必要です。

現時点では、クラスがロードされるとフィルター チェーンが構築されます。クラスがロードされた後、ある時点でフィルターチェーンを再構築する必要があります。

これは、フィルタ チェーンが MyController 用に構築されたに次のようなことを実行できる拡張機能を使用する Rails プロジェクト (Spree、Radiant も影響を受ける可能性があると推測しています) と関係があります。

MyController.class_eval do
  before_filter :my_filter_method
end

ApplicationController.class_eval do
  before_filter :app_filter_method
end

ここでの問題は、app_filter_methodフィルターがMyController フィルター チェーンに追加されないことです。これは、MyController のフィルター チェーンが ApplicationController のフィルター チェーンの以前のコピーから構築されているためです。ApplicationController のフィルター チェーンのこのコピーには、まだフィルターが適用されていませんapp_filter_method

これまでのところ、FilterChain の再構築が行われる可能性のある場所が 2 つあります。

1) MyController.filter_chain で呼び出されるたびに

2) オンデマンドでリロード可能。したがって、 MyController.reload_filter_chain は、チェーン内の MyController のサブクラスのフィルターを使用して、フィルター チェーンを再構築します。

おそらく、リクエストごとにフィルター チェーンを構築する ReloadableFilterChain のような FilterChain のサブクラスを指定することで、それが可能になるかもしれません。

Ruby on Rails 2.3.2 用の GitHub の filters.rb のソースへのリンクを次に示します。

filter_chain メソッド (573 行目)

FilterChain クラス (10 行目)

ここにいる皆さんの何人かが、これを行う方法についての洞察やアドバイスを持っていることを願っていました.

どんな助けでも大歓迎です。

エリオット

要求された詳細:

Spree は、拡張機能を使用して動作を変更する Rails アプリです。

コントローラーにフィルターを追加するために拡張機能が使用される場合があります (質問のコード例など)。使用例の 1 つは、静的コンテンツ拡張です。

静的コンテンツ拡張機能を使用すると、データベースに格納されている HTML ページを、指定した要求パスに対して表示することができます。たとえば、/products リクエスト パスに対して Spree が表示するデフォルトのコンテンツの代わりに、これらの HTML ページの 1 つを表示できます。

静的コンテンツ拡張機能は、すべての要求をフィルタリングし、パスをチェックします。パスがデータベース内のいずれかのページと一致する場合、フィルターはそのページをレンダリングします。

静的コンテンツ拡張は、そのフィルターを次のように宣言します。

Spree::BaseController.class_eval do
  before_filter :render_page_if_exists

  def render_page_if_exists
    ...
  end
end
4

1 に答える 1

0

Rails 1.0 では、フィルタ チェーンがこのようにキャッシュされることはなかったので、問題にはなりませんでした。

フィルタ チェーンがキャッシュされるようになった理由は、パフォーマンスのためです。キャッシュしない理由はほとんどありません。ダイナミックにしたい他の人を探し回ったところ、1つの投稿しか見つかりませんでした。したがって、このような場合を除き、アプリの起動後にフィルター チェーンを動的または再読み込み可能にする必要はほとんどないようです。

これを念頭に置いて、 FilterChain.reload のようなメソッドは、パフォーマンスの向上を維持するための良い方法だと思います.

Spree では、拡張機能をロードした後に FilterChain.reload を呼び出すことができました。以前のコメントで提案した解決策 (before_filter にパッチを当てる) よりも、Rails コアにとって有用であるというより良いショットを得たと思うので、これを好みます。

FilterChain.class_eval do

  # Reloads all filter chains on all controllers, working from the ApplicationController down
  # through the class hierarchy.  e.g. Spree::BaseController would get its filter chain reloaded
  # before its subclasses like ProductsController. We do this as ProductsController's filter chain
  # relies on a copy of the Spree::BaseController filter chain.
  def self.reload
    # ApplicationController.filter_chain does not need reloading, it will be the only correct
    # filter chain for sure as it is not inherited from a superclass.
    reload_child_filter_chains(ApplicationController)
  end

  def self.reload_child_filter_chains(controller_class)
    controller_class.immediate_subclasses.each do |controller_child|
      # Reload filter chain on each controller who's immediate parent is the controller_class
      controller_child.filter_chain.merge_filter_chain(controller_class.filter_chain)
      # Reload the children of controller_child
      reload_child_filter_chains(controller_child)
    end
  end

  # New instance method on FilterChain to merges the given parent chain into itself.
  def merge_filter_chain(parent_chain)
    # Compare self and parent_chain and insert any parent_chain filters that
    # are missing from self.  You may need special handling for
    # Filters that were marked for skipping or with :only, etc. conditions.
    ...
  end
end

ここのコメントから取得:

Spree issue 653 拡張機能でフィルタを指定すると、フィルタがないフィルタ チェーンが作成される可能性がある

于 2009-08-15T09:22:14.120 に答える