我在瀏覽this gem的源代碼,我發現content_tag的使用讓我困惑不已。Rails content_tag方法
def render(view)
view.content_tag(name, attributes[:content], attributes.except(:content))
end
我不明白爲什麼在視圖上調用content_tag。我通常使用它作爲助手來生成HTML標記,但我從來沒有把它稱爲一種方法。
我在瀏覽this gem的源代碼,我發現content_tag的使用讓我困惑不已。Rails content_tag方法
def render(view)
view.content_tag(name, attributes[:content], attributes.except(:content))
end
我不明白爲什麼在視圖上調用content_tag。我通常使用它作爲助手來生成HTML標記,但我從來沒有把它稱爲一種方法。
最常見的,content_tag
被稱爲在視圖的情況下 - 所以,你不需要調用view.content_tag
,因爲該視圖知道如何來應對content_tag
(和簡單地調用content_tag
是與調用self.content_tag
)。
您正在顯示的render
方法存在於繼承自Tag
的類MetaTag
中。 Tag
是一個普通的舊Ruby對象(PORO),所以它不知道如何響應content_tag
。
但是,如您所見,render
方法將視圖作爲參數。當然,view
的對象知道如何迴應content_tag
。因此,調用view.content_tag
是MetaTag
能夠呈現內容標記的方式。
這幾乎是Presenter模式的一個實例(不同的人使用不同的術語)。 Ryan Bates在這個here上有一個很好的RailsCast。
對於你的問題在評論中,Rails不知道view
是ActionView::Base
的一個實例。您有責任傳遞實際視圖實例。我傾向於通過控制器,以便可以訪問視圖和參數。也許是這樣的:
class FooController < ApplicationController
def foo_action
FooPresenter.present(self)
end
end
和...
class FooPresenter
class << self
def present(controller)
new(controller).present
end
end # class methods
#===================================================================
# instance methods
#===================================================================
def initialize(controller)
@controller = controller
end
def present
content_tag :div, data: {foo: params[:foo]}, class: 'bar'
end
private
def controller() @controller end
def view() controller.view_context end
def params() controller.params end
def method_missing(*args, &block)
view.send(*args, &block)
end
end
通過包括method_missing
方法,我再也不用打電話view.content_tag
。我可以撥打content_tag
。 FooPresenter不會找到該方法,因此會將該呼叫發送到view
,該方法將被發現並執行。
再一次,瑞安在解釋所有這些方面做得很好。
不用過多的細節,content_tag
是ActionView::Helpers::TagHelper
類中的方法。我相信這個類的對象要麼自動包含在Rails視圖中,要麼Rails視圖對象委託給這個對象。
這種特殊的寶石需要一個ActionView::Base
對象作爲參數用於其render
方法,以便該方法可以訪問content_tag
方法,該方法是ActionView::Helpers::TagHelper
一部分。這是一個體面的Dependency Injection的例子,這是面向對象編程的基本原理。
感謝您的解釋和指向我的RailsCast。我仍然不明白一件事:Rails如何知道'view'是Rails視圖的'ActionView :: Base'視圖實例? – davideghz
您的更新回答很好,但是您能否指出我在ActionView :: Base實例實際傳遞給方法的鏈接源代碼(gem)中的確切行? – davideghz
哇!你真的讓我爲這個工作......(開玩笑)。因此,在參考創業板的仔細檢查,文檔提供**使用控制器元標記**和**鑑於**使用元標籤 - 這表明,這並不遵循PORO演示模式(我們對此深感抱歉)。相反,MetaTag方法通過'meta-tags/lib/meta_tags.rb'的第36和37行調用的包含方法包含在'ActionController :: Base'和'ActionView :: Base'中。在這些情況下,'view'始終可用。謝謝:) – jvillian