2009-08-14 55 views
0

我想在Ruby on Rails 2.3.2中使用過濾器鏈的更動態的方式。Ruby on Rails FilterChain內部 - 如何使其可重新加載?

目前,過濾器鏈是在加載類時構建的。我非常需要在類加載後的某個時間點重建過濾器鏈。

這是與使用擴展,它可以做這樣的事情後過濾器鏈已建成一個myController的Rails項目(施普雷,輻射也可能會受到影響,我猜)做:

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過濾器。

我能想到的2個地方,到目前爲止,該FilterChain的重建可能發生在:

1)每次它被稱爲上MyController.filter_chain

2)增值的需求。因此,MyController.reload_filter_chain將使用鏈中MyController的子類的過濾器重建過濾器鏈。

也許指定FilterChain的子類,如ReloadableFilterChain爲每個請求構建過濾器鏈可能會這樣做 - 思考?

這裏是鏈接在GitHub上,爲Ruby filters.rb來源on Rails的2.3.2:

The filter_chain method (line 573)

The FilterChain class (line 10)

我在這裏希望你們當中有些人可能有一些見解或如何做到這一點的建議。

任何幫助非常感謝。

艾略特

更多細節的要求:

施普雷是使用擴展修改行爲Rails應用程序。

有時擴展用於向控制器添加過濾器(例如在問題中的示例代碼中)。一個示例使用是靜態內容擴展。

靜態內容擴展允許您顯示存儲在數據庫中的HTML頁面,以顯示您指定的任何請求路徑。例如,您可以顯示其中一個HTML頁面,而不是顯示/ products請求路徑的默認內容Spree。

靜態內容擴展篩選所有請求並檢查路徑。如果路徑與數據庫中的某個頁面匹配,那麼過濾器將呈現該頁面。

靜態內容擴展聲明其過濾,像這樣:

Spree::BaseController.class_eval do 
    before_filter :render_page_if_exists 

    def render_page_if_exists 
    ... 
    end 
end 
+0

更多細節上你想實現將是有益的。 – jonnii 2009-08-14 13:18:38

+0

增加了*少許*更多細節。有什麼具體的我可以添加幫助? – 2009-08-14 13:29:55

+0

我更感興趣的原因。 – jonnii 2009-08-14 14:07:59

回答

0

早在Rails的1.0過濾器鏈並沒有用來獲取緩存像這一點,所以不會有問題。

過濾器鏈被緩存的原因是性能。沒有理由不緩存它。從尋找其他人想要它是動態的,我發現只有一個職位。所以看起來應用程序啓動後,過濾器鏈幾乎不需要動態或可重新加載,除非遇到類似的情況。

考慮到這一點,我認爲像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 Specifying filters in extensions can create filter chains missing filters