2009-08-14 6 views
0

Ich möchte eine dynamischere Art der Arbeit mit Filterketten in Ruby on Rails 2.3.2 haben.Ruby on Rails FilterChain Interna - wie man es nachladbar macht?

Im Moment wird die Filterkette aufgebaut, wenn die Klassen geladen werden. Ich habe ein ganz besonderes Bedürfnis, dass die Filterkette zu einem bestimmten Zeitpunkt nach dem Laden der Klassen neu aufgebaut wird.

Dies ist mit einem Rails-Projekt (Spree, Radiant ebenfalls betroffen sein kann ich vermute) zu tun, die Erweiterungen verwendet, die nach der Filterkette wurde für MyController gebaut Dinge wie diese tun können:

MyController.class_eval do 
    before_filter :my_filter_method 
end 

ApplicationController.class_eval do 
    before_filter :app_filter_method 
end 

Das Problem hier ist, dass der app_filter_method Filter wird nicht der MyController Filterkette hinzugefügt werden. Dies liegt daran, dass die Filterkette von MyController aus einer früheren Kopie der Filterkette von ApplicationController aufgebaut ist. Diese Kopie der Filterkette von ApplicationController tut nicht, noch haben Sie den app_filter_method Filter darauf angewendet.

kann ich 2 Plätze denken, so weit, dass der Wiederaufbau der filter in passieren könnte:

1) Jedes Mal, wenn es auf MyController.filter_chain

2) nachladbare auf Anfrage genannt. Also wird MyController.reload_filter_chain die Filterkette neu aufbauen, wobei die Filter aus MyControllers Unterklassen in der Kette verwendet werden.

Vielleicht eine Unterklasse von FilterChain wie ReloadableFilterChain, die die Filterkette für jede Anfrage baut, könnte es tun - Gedanken?

Hier sind die Links zur Quelle der filters.rb auf GitHub, für Ruby on Rails 2.3.2:

The filter_chain method (line 573)

The FilterChain class (line 10)

Ich war hier einige von Ihnen Hoffnung, vielleicht einen kleinen Einblick haben oder Ratschläge, wie dies zu tun ist.

Jede Hilfe sehr geschätzt.

Eliot

Weitere Einzelheiten wie gewünscht:

Spree ist eine Rails-Anwendung, die Erweiterungen verwendet Verhalten zu ändern.

Manchmal wird eine Erweiterung verwendet, um einen Filter zu einem Controller hinzuzufügen (wie im Beispielcode in der Frage). Ein Beispiel ist die statische Inhaltserweiterung.

Die Erweiterung für statische Inhalte ermöglicht das Anzeigen von in der Datenbank gespeicherten HTML-Seiten, die für jeden von Ihnen angegebenen Anforderungspfad angezeigt werden. Sie können beispielsweise eine dieser HTML-Seiten anstelle des Standardinhalts anzeigen, den Spree für den/products-Anfragepfad anzeigt.

Die statische Inhaltserweiterung filtert alle Anfragen und prüft den Pfad. Wenn der Pfad mit einer der Seiten in der Datenbank übereinstimmt, rendert der Filter die Seite.

Die statische Inhalt Erweiterung erklärt seine Filter in etwa so:

Spree::BaseController.class_eval do 
    before_filter :render_page_if_exists 

    def render_page_if_exists 
    ... 
    end 
end 
+0

Weitere Details auf, was Sie versuchen wäre nützlich zu erreichen. – jonnii

+0

Ein * kleines * Detail hinzugefügt. Gibt es etwas Spezifisches, das ich hinzufügen kann, um zu helfen? –

+0

Ich interessiere mich mehr für das Warum. – jonnii

Antwort

0

Zurück in Rails 1.0 die Filterkette nicht so zwischengespeichert bekommen verwendet und wäre so kein Problem gewesen.

Der Grund, warum die Filterkette zwischengespeichert wurde, war die Leistung. Es gibt wenig Grund, es nicht zwischenzuspeichern. Aus der Suche nach anderen Menschen, die es dynamisch finden wollten, fand ich nur einen Beitrag. Es sieht also so aus, als ob die Filterkette nach dem Start der App selten dynamisch oder nachladbar sein muss, es sei denn, Sie erhalten einen Fall wie diesen.

In diesem Sinne denke ich, eine Methode wie FilterChain.reload wäre ein guter Weg, um die Performance-Gewinne zu halten.

In Spree konnte FilterChain.reload nach dem Laden der Erweiterungen aufgerufen werden. Ich bevorzuge dies mit der Lösung, die ich in einem früheren Kommentar (patchen vor dem Filter) vorgeschlagen habe, da ich denke, dass es eine bessere Einstellung hat, um für den Kern von Rails nützlich zu sein.

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 

von Kommentaren hier Genommen:

Spree issue 653 Specifying filters in extensions can create filter chains missing filters