在render 與 redirect_to 中看過,某個動作執行過後,預設執行的render方法會尋找app/views資料夾下,與控制器同名資料夾下的樣版檔案來呈現畫面。例如若請求tests/some,在動作處理過後,預設會尋找app/views/tests資料夾下some.html.erb檔案來呈現畫面,tests資料夾名稱是控制器名稱,some名稱是動作名稱,html.erb表示用內嵌Ruby程式碼(Embedded Ruby)的方式,產生HTML格式的回應,你也可以用xml.erb,表示用嵌入式Ruby程式碼來產生XML格式,使用json.erb、csv.erb、js.erb也是同樣的道理。
Erb是Rails預設的樣版引擎,或稱為樣版處理器(Template Handler),先前看過<%= %>與<% %>,都是Erb標籤,<%= %>用來將=之後的值、方法傳回值或運算結果等輸出為回應的一部份,如果只是運算流程,不需要輸出為回應,則可以使用<% %>。例如 基本 CRUD 程式 中看過的片段:
<ul>
<% @pages.each do |page| %>
<li>
<%= link_to page.title, page.url %>
<%= link_to "Details", :controller => 'bookmarks', :action => 'show', :id => page %>
<%= link_to "Edit", :controller => 'bookmarks', :action => 'edit', :id => page %>
<%= link_to "Delete", :controller => 'bookmarks', :action => 'destroy', :id => page %>
</li>
<% end %>
</ul>
雖然說內嵌Ruby程式碼,不過要寫註解時,並不能這麼寫(%與#分開):
<% # print self.class %>
#之後會整個被忽略,所以就看不到%>。你要嘛就換行:
<%
# print self.class
%>
要嘛就使用<%#作開頭(%#連在一起)。例如:
<%# print self.class %>
Rails也內建Builder樣版引擎,用來產生XML格式的回應,只要檔名以.builder結尾。例如在 respond_to 與 respond_with 中看過:
- index.xml.builder
xml.pages do # 根節點 <pag es></pages>
@pages.each do |page|
xml.page do # 節點 <page></page>
xml.title page.title # 節點 <title></title>
xml.url page.url # 節點 <url></url>
xml.description page.description # 節點 <description></description>
end
end
end
在 Action View Base 中可以看到一些Builder的例子(若對產生XML的原理有興趣,可以參考 BasicObject)。
<%= render "navigation" %>
那麼與樣版檔案所在資料夾下_navigation.html.erb的內容會被加入目前樣版檔案,注意檔案一開頭有個底線,這稱為區部樣版,如果要使用路徑。例如:
<%= render "shared/navigation" %>
那會尋找app/views/shared資料夾下_navigation.html.erb檔案。假設樣版中原本有個呈現錯誤訊息的片段:
<% if @errors %>
<ul style="color: rgb(255, 0, 0);">
<% @errors.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<% end %>
這是個通用的錯誤呈現片段,如果你想要將這個片段抽出為區部樣版_errors.html.erb,不過有時錯誤訊息並不一定是放在實例變數中,因此你的區部樣版設計為:
- _errors.html.erb
<% if errors %>
<ul style="color: rgb(255, 0, 0);">
<% errors.each do |error| %>
<li><%= error %></li>
<% end %>
</ul>
<% end %>
這個區部樣版中有個區域變數errors,可以在繪製區部樣版時,使用:locals指定區部樣版中的區域變數值。例如:
<%= render :partial => "errors", :locals => { :errors => @errors } %>
每個區部樣版都會有個區域變數與區部樣版本身名稱同名。例如:
<%= render :partial => "address", :object => @office_addr %>
在_address.html.erb中,會有個區域變數address,可以使用:object指定這個變數參考至哪個物件。如果你有個模型物件,也可以有簡寫的方式:
<%= render @address %>
@address必須是ActiveRecord::Base實例,可透過model_name取得名稱,假設模型為Address,以上會尋找_address.html.erb,並將其中區域變數address設定為@address參考的物件。
如果你有個樣版內容:
- index.html.erb
<h1>Bookmark Online</h1>
<ul>
<% @pages.each do |page| %>
<li>
<%= link_to page.title, page.url %>
<%= link_to "Detail", bookmark_path(page), :method => :get %>
<%= link_to "Edit", edit_bookmark_path(page), :method => :get %>
<%= link_to "Delete", bookmark_path(page), :method => :delete %>
</li>
<% end %>
</ul>
<%= link_to "New", new_bookmark_path %>
當中使用了each方法來迭代每筆資料要呈現的內容。你可以撰寫一個:
- _page.html.erb
<li>
<%= link_to page.title, page.url %>
<%= link_to "Detail", bookmark_path(page), :method => :get %>
<%= link_to "Edit", edit_bookmark_path(page), :method => :get %>
<%= link_to "Delete", bookmark_path(page), :method => :delete %>
</li>
然後原樣版就可以改為:
- index.html.erb
<h1>Bookmark Online</h1>
<ul>
<%= render :partial => "page", :collection => @pages %>
</ul>
<%= link_to "New", new_bookmark_path %>
_page.html.erb中的區域變數page會自動設為@pages.each每次迭代的物件,你也可以自行設定每次迭代後的物件,由哪個區域變數名稱參考。例如:
- index.html.erb
<h1>Bookmark Online</h1>
<ul>
<%= render :partial => "page", :collection => @pages, :as => :bookmark %>
</ul>
<%= link_to "New", new_bookmark_path %>
如此一來,每次迭代的物件,將在_page.html.erb中由bookmark名稱參考,因此區域樣版要改為:
- _page.html.erb
<li>
<%= link_to bookmark.title, bookmark.url %>
<%= link_to "Detail", bookmark_path(bookmark), :method => :get %>
<%= link_to "Edit", edit_bookmark_path(bookmark), :method => :get %>
<%= link_to "Delete", bookmark_path(bookmark), :method => :delete %>
</li>