這一篇的重點是除了 Helper 和 Partial 外,還有什麼工具是可以拿來用來整理 View 的。
11. content_for ( yield )
有些開發者不是很了解 Rails 的 yield
是拿來作什麼的。你可以理解成 跳躍到定點執行
。
這招常被用在一個情景上: Best Practices for Speeding Up Your Web Site 中的 put javascript at bottom。
在調整前端 performance 時,最常見也最有效的一招就是,把肥大的 JavaScript 放在最底端讀入執行,因為很多 JS 都是 document.ready 才會被執行。
但是,如果開發者只是把 javascript_include_tag
丟到 view 的底下,如:
<%= stylesheet_link_tag "application" %>
<%= yield %>
<%= javascript_include_tag "application" %>
其實這樣有時候是不會動的,因為當你的 View 裡面需要寫 inline javascripts 時,如:
your content stuff
<script type= "text/javascript">
your script here
</script>
會得到 javascript undefined。
這通常是因為 inline javascripts 呼叫了 jQuery 裡面的函式,而 inline javascripts 被執行的比 jQuery 被讀入的時間早,所以會出現 undefined。
所以你只好被迫將優美的
<%= stylesheet_link_tag "application" %>
<%= yield %>
<%= javascript_include_tag "application" %>
改回
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= yield %>
其實要解決這樣的問題。只需要把 View 改成這樣:
<%= stylesheet_link_tag "application" %>
<%= yield %>
<%= javascript_include_tag "application" %>
<%= yield :page_specific_javascript %>
需要插入 inline javascripts 的地方再這樣寫,這樣 inline javascripts 就會在正確的位置 page_specific_javascript
被執行。
your content stuff
<%= content_for :page_specific_javascript do %>
<script type= "text/javascript">
your script here
</script>
<% end %>
套用在 sidebar 上
這招也可以用在 sidebar 上。很多內容網站裡面常常需要放置側邊欄廣告,而這些網站通常有嚴重的 performace issue,原因是它們的 sidebar 都是這樣被設計的:
使用一個全站的 @instance_variable 控制。造成 @instance_variable 到處污染以及 logic in view
<div class="main">
main content
</div>
<div class="sidebar">
<% case @ad_type %>
<% when foo %>
<%= render "ad/foo"%>
<% when bar %>
<%= render "ad/bar"%>
<% else %>
<%= render "ad/default"%>
<% end %>
</div>
其實用 yield
就可以巧妙的避開這種問題。將 View 改成
<div class="main">
<%= yield %>
</div>
<div class="sidebar">
<%= yield :sidebar %>
</div>
再把各個 view 裡面需要呼叫的 sidebar 拆開獨立呼叫即可
main content
<%= content_for :sidebar do %>
<%= render "ad/foo"%>
<% end %>
12. Decoration in Controller
有些開發者學到了 yield
這招,就會開始覺得這招實在太棒了,覺得應該可以開始把 Logic 拆散在 View 裡面。如把 meta 定義在 View 裡面:
<%= content_for :meta do %>
<meta content="xdite's blog" name="description">
<meta content="Blog.XDite.net" property="og:title">
<% end %>
其實過猶不及
也是不好的。如果是關於 meta 的部分,放在 Controller 裡面其實是比較整理和好收納的。反而可以
- 清楚的標明這個 action 的作用
- 避免邏輯散落。
def show
@blog = current_blog
drop_blog_title @blog.name
drop_blog_descption @blog.description
end
<%= stylesheet_tag "application" %>
<%= render_page_title %>
<%= render_page_descrption %>
13. Decoration using I18n
大家對 Rails 的 I18n 機制的印象都是「作翻譯」,其實 I18n 也可以拿來做 "Decoration"。如:
def render_user_geneder(user)
if user.gender == "male"
"男 (Male)"
else
"女 (Female)"
end
end
其實可以被簡化成
def render_user_gender(user)
I18n.t("users.gender_desc.#{user.geneder}")
end
這樣的情景其實也被可以套用在這種 yes/no ( true/false) 的場景:
def render_book_purchase_option(book)
if book.aviable_for_purchase?
"Yes"
else
"No"
end
end
善用 I18n,可以節省不少裝飾用的程式碼。
Maintainable Rails View 系列文目錄