2012-05-06 71 views
19

我想使用導軌熟悉的助手,但功能稍有變化。我看到它的方式,我希望能夠做一些事情,如:覆蓋導軌助手訪問原始

module AwesomeHelper 
    #... create alias of stylesheet_link_tag to old_stylesheet_link_tag 
    def stylesheet_link_tag(*args) 
    if @be_awesome 
     awesome_stylesheet_link_tag *args 
    else 
     old_stylesheet_link_tag *args 
    end 
    end 
end 

我看到它的方式,我有三種選擇:

  1. 猴子補丁:重新打開軌道助手模塊。如果Rails團隊改變了他們的幫手模塊的名字,我的代碼就變成了脆弱的源泉。不是無法克服的,但並不理想。
  2. 使用不同的方法名稱:試圖堅持共軌接口可能是我的失敗。我的更改可能會成爲其他開發人員混淆的來源
  3. 分離方法(新):不確定這是否可行,或者它是否與1具有相同的缺點。是否會研究此問題,但這可能是一個好結果初始點。

所以這裏的問題是,我堅持這些次優解決方案之一,還是有另一種方式,我沒有考慮?如果我去選項3,有沒有辦法做到這一點,而不直接處理鐵軌輔助模塊?

(注:我已刪除的背景下,因爲它增加了沒什麼問題)

回答

30

有一個比任何列出的選項更好的方法。只需使用super

module AwesomeHelper 
    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     super 
    end 
    end 
end 

它將覆蓋AwesomeHelper stylesheet_link_tag將確保,當stylesheet_link_tag被調用,紅寶石將它擊中ActionView::Helpers::AssetTagHelper之前遇到它的方法查找路徑。如果@be_awesometrue,那麼您將負責並在那裏停止執行任務,如果沒有,則在沒有括號的情況下調用super將透明地傳遞所有參數直至實現Rails。這樣你就不必擔心Rails的核心團隊在你身上移動東西!

+0

你知道嗎......這太瘋狂了,我試圖絞盡腦汁想出爲什麼我認爲這是行不通的!我今晚會嘗試它,如果它有效,我會用我的大腦說一些嚴厲的話,可能涉及到一堵磚牆。當然,接受你的答案後......:D – user208769

+1

@ user208769 Hehehe。棒極了。據我所知,在任何情況下,這種方式的優先方法通常是優選的。 [Class#ancestors](http://ruby-doc.org/core-1.9.3/Module.html#method-i-store)在確定劫持方法的方法查找路徑中的一個好位置方面確實很有幫助調度(或者您的自定義模塊與覆蓋需要包含在最好的效果)。 – Cade

+0

什麼? :) 你在開玩笑吧!這是一個巨大的困擾!你的方式,你必須在每個包括AssetTagHelper的類中包含你的幫手。時光飛逝,你或其他人可能忘記需要你的補丁包括在內。您只需包含AssetTagHelper並開始懷疑:爲什麼我的網站現在看起來不一樣?當你和補丁製作者是同一個人時,這很好。但是,如果不是? – jdoe

6

我不使用這種寶石,所以我會回答你在一個更通用的方法。

假設你想將呼叫記錄到link_to助手(是的,人爲的例子,但顯示了這個想法)。通過查看API,您可以瞭解位於ActionView::Helpers::UrlHelper模塊內的link_to。所以,你在你的,比方說,config/initializers目錄包含以下內容創建一些文件:

# like in config/initializers/link_to_log.rb 
module ActionView::Helpers::UrlHelper 

    def link_to_with_log(*args, &block) 
     logger.info '**** LINK_TO CALL ***' 
     link_to_without_log(*args, &block) # calling the original helper 
    end 

    alias_method_chain :link_to, :log 
end 

的該功能的核心 - alias_method_chain(點擊)。在定義方法xxx_with_feature後使用它。

+0

呀,這個方法是我的意思是「猴子打補丁的具體軌道模塊」 - 這工作得很好,但如果Rails核心改變自己的模塊名稱,我的代碼休息。這可能不是什麼大問題,但我很好奇看看是否有其他解決方案。這就是說,忘記了alias_method_chain,謝謝你提醒我! – user208769

+0

P.S:已更新問題以刪除該寶石示例。希望這種佈局不那麼令人困惑!謝謝。 – user208769

+0

風險始終存在!如果您擔心'alias_method_chain',那麼您不應該:從版本1.4.0(2007年)開始存在。如果你擔心你的程序的其他部分,那麼確保體面的測試覆蓋率。 – jdoe

2

我真的會鼓勵你考慮你的選項#2,以一種對調用者來說很明顯的方式重寫rails方法的行爲。

您的新方法應該叫做awesome_stylesheet_link_tag,以便其他Rails開發人員可以讀取您的代碼並詢問「鏈接標記有什麼如此棒的事實?」。

作爲一個較小的變化,你可以做覆蓋,但通過:awesome => true作爲一個參數,所以他們至少有一個線索,一些事情正在進行。

更改廣泛使用的方法(如stylesheet_link_tag)的行爲會造成潛在的未來誤解,無需任何必要。

+0

感謝您的輸入。雖然通常我都同意,在這種特殊情況下,我認爲一致性是有道理的 - 我這樣做是爲了使用wicked_pdf,並使用完全相同的代碼生成PDF或網頁。雖然wicked_pdf在默認情況下會像您說的那樣執行(wicked_pdf_stylesheet_link_tag),但它對我來說需要太多重複,而且我認爲如果您生成PDF,功能可能會發生變化是可以接受的。但是你提出了一個很好的觀點,並提供了一些便利的提示,所以謝謝。 – user208769

4

嘗試使用alias_method

module AwesomeHelper 
    alias_method :original_stylesheet_link_tag, :stylesheet_link_tag 

    def stylesheet_link_tag(*sources) 
    if @be_awesome 
     awesome_stylesheet_link_tag *sources 
    else 
     original_stylesheet_link_tag *sources 
    end 
    end 
end