2012-04-05 41 views
3

我在理解alias_method/alias_method_chain時有點困難。我有以下代碼:alias_method,alias_method_chain和self.included

module ActionView::Helpers 
    module FormHelper 

    alias_method :form_for_without_cherries, :form_for 

    def form_for(record, options = {}, &proc) 
     output = 'with a cherry on top'.html_safe 
     output.safe_concat form_for_without_cherries(record, options = {}, &proc) 
    end 
    end 
end 

這正是我想要做它什麼 - 附加「與頂部的櫻桃」任何form_for呼叫的頂部。

但我的理解是這是不好的代碼有幾個原因。首先,它不會鏈接form_for(?)的任何其他覆蓋,所以如果我要編寫第二個form_for方法,它附加了「又一個櫻桃頂部」,它不會顯示。其次,alias_methodalias_method_chain是一些過時的解決方案,我應該使用self.included &而不是發送到模塊。

但我不能得到self.included來調用這個form_for方法 - 它只是不斷調用父類。這是我想要的:

module CherryForm 
    def self.included(base) 
    base.extend(self) 
    end 

    def form_for(record, options = {}, &proc) 
    output = 'with a cherry on top'.html_safe 
    output.safe_concat super(record, options = {}, &proc) 
    end 
end 

ActionView::Helpers::FormHelper.send(:include, CherryForm) 

我上面的解決方案的工作原理,但我懷疑這是做事的錯誤方式。如果任何一位紅寶石老手能夠向我展示這樣做的更優雅的方式 - 和/或爲什麼第二種解決方案沒有被調用 - 我會很感激。

+2

至於爲什麼第二種方法不起作用,請參閱:http://stackoverflow.com/questions/5944278/overriding-method-by-another-defined-in-module – tsherif 2012-04-05 17:38:55

+0

這有助於很多。非常感謝 – PlankTon 2012-04-05 18:10:36

回答

4

當你修補某個東西時,你必須重新定義該方法,因爲沒有超類繼承(所以你不能使用第二個代碼片斷)。

複製當前的方法實現,並添加自己只是自找麻煩,所以這是alias_method用武之地。

alias_method :form_for_without_cherries, :form_for 

它實際上創建了一個克隆原來的方法,你可以用它來代替超。事實上,你不能鏈猴子補丁不是一個錯誤,這是一個功能。

rails alias_method_chain方法確實被棄用,但僅僅是因爲它從一開始就是一個糟糕的主意。然而,alias_method是一種純粹的ruby方法,當正確使用時可以提供一種猴子修補代碼的優雅方式,這就是爲什麼我很確定它不會很快消失。

+0

非常好 - 謝謝vise。 – PlankTon 2012-04-05 21:52:20