第二節 ActionController – 動作控制器
RJS模板被無縫地放到了Rails框架內,就像RHtml與Builder模板。這意味著RJS模板被像其它模板類型一樣被渲染。遵守同樣的約定及大多數同樣的render選項可以被用在你的控制器動作內。下面是一個RJS如何與ActionController工作的浏覽。
RJS templates fit seamlessly into the Rails framework, just like RHtml and Builder templates. This means that RJS templates are rendered just like the other type of template. The same conventions are followed and most of the same render options can be used in your controller actions. The following is an overvIEw of how RJS works with ActionController.
一、Default VIEw – 默認視圖
默認情況下,控制器搜索與當前運行的動作同名的模板。注意控制器在找到.rJS 模板之前將會尋找任何 .rHtml 或 .rXML 模板。如果你有個模板名為product.rHtml 以及一個名為 product.rJS 的其它模板,ActionController將渲染product.rHtml並發送它做為一個 text/Html的Content-Type 頭來應答。這不會創建你希望的結果並且可能難於調試,如果你不想在日志內收到任何錯誤的話。如果你有product.rHtml與product.rJS模板兩者的話,你可以指出哪個類型的模板是你想渲染的,通過在指定動作時包含文件的擴展名。
By default, the controller searches for a template with same name as the action that is executing. One caveat is that the controller will find any .rhtml or .rXML templates before finding the .rjs template. If you have a template named product.rhtml and another template named product.rJS, ActionController will render product.rhtml and send it as the response with a Content-Type header of text/html. This won't create the results you expected and may be tricky to debug, since you won't receive any errors in the log. If you do have have both a product.rHtml and a product.rJS template you can specify which type of template you want to render by including the file extension when specifying the action.
def product
# skip product.rHtml or product.rXML if either exists
render :action => "product.rJS"
end
像你從代碼中看到的,我們通過提供一個擴展名.rJS,已明確地指定了我們想渲染一個RJS模板。用來配置你希望返回的應用類型的其它方式是用一個新的respond_to()塊。該respond_to()塊將依據HTTP Accept header來返回適當的應答。由Prototype庫生成的遠程AJax應答指定 Accept header 為text/Javascript, text/Html, application/xml, text/XML, */*。這告訴Rails AJax請求更喜歡一個 JavaScript 應答,但是不可能的話,則將接受列表內其它的類型。下面代碼簡單地幫助演示了這個概念。
As you can see from the code, we've explicitly specifIEd that we want to render an RJS template by tacking on the extension .rJS. Another way to configure the type of response you'd like to return is with the new respond_to() block. The respond_to() block will return the appropriate response depending on the HTTP Accept header. The remote
def product
respond_to do |format|
format.html # all Html requests
format.JS # all
format.XML # all XML requests
end
end
上面的 respond_to() 塊返回基於 Accept header 上的當前內容並且也示范了我們有三種內容變量類型:HTML(product.Html),JavaScript(product.rJS)與XML(product.XML)。你也可以進一步定義 respond_to() 塊,這通過在代碼塊內為每個類型指定更多細節。
The respond_to() block above returns the correct content based on the Accept header and also illustrates that we have three types of content available: HTML (product.Html), JavaScript (product.rJS) and XML (product.XML). You can also further customize the respond_to() block by specifying more details in a code block following each type.
def product
respond_to do |format|
format.Html { Flash["notice"] = 'here is a product' }
format.js { render :action => "product_rjs.rJS" }
format.xml { render :xml => @product.to_XML }
end
end
上面代碼塊內定制的應答是:Flash內容被添加給Html應答,RJS模板渲染JavaScript應答內指定的 product_rjs.rJS,以及構建在 ActiveRecord 內的 to_XML() 特性被用於生成 XML 應答而不是在 XML 應答內使用 Builder模板。如你所見,與 HTTP Accept header 結合的 pespond_to() 塊允許你把分散在控制器內其它地方的代碼放到一個單獨的代碼塊內。
The customizations to the responses in the code above are as follows: Flash content is added to the Html response, the RJS template to render is specifIEd as product_rjs.rJS in the JavaScript response, and the to_xml() feature built into ActiveRecord is utilized to generate the XML response instead of using a Builder template in the XML response. As you can see, the combination of the HTTP Accept header with the respond_to() block allows you to consolidate a lot of otherwise unwIEldy controller code into a single code block.
二、Layouts – 布局
Rails 允許最小驚奇原則,以便在你渲染RJS模板時,ActionController能足夠跳過布局而不會驚奇。你不需要關心有關傳遞 :layout => false 給任何要渲染一個RJS模板的動作。
Rails follows the principle of least surprise, so it isn't surprising that ActionController is smart enough to skip layouts whenever you render an RJS template. You don't need to worry about passing :layout => false to any action that renders an RJS template.