over 4 years ago

關於MVC

參考文章

什麼是View

View基本上就是負責處理視覺呈現的地方,在rails的開發中view就是負責放html碼的地方,也就是前端呈現。

什麼東西應該放在 View

原則上View只應該出現跟前端呈現有關的東西,儘量不要把判斷以及邏輯相關的code放在View,例如以下的例子就是不好的做法:

<% if current_user %>
    <p><%= current_user.name %></p>
<% else %>
    <p>Not Logined</p>
<% end %>

這個例子中在view判斷使用者是否登入,且還對使用者讀取name的欄位
比較好的做法是將if else改寫在partial中,並把current_user.name用helper包起來。
這樣html code的好讀性就可以大大提升。
請參考本章詳細介紹。

什麼是 helper

Helper是rails簡化View的方法之一,rails有內建的一系列helper可以用,常見的有link_to、form_for、content_tag等等。
此外我們也可以自己建立Helper,將View中需要邏輯判斷或是不斷重複的code寫進helper內,例如:

module BoardsHelper
#回傳board的name,避免在view中做太多判斷

  def render_board_name(board)
    if board.present?
        board.name 
    else
        "unknown"
    end
  end
#常常重複的區段也可以寫進helper,統一管理

  def render_board_name_path(board)
    link_to(board.name, board_path(board)) 
  end
end

在view中可以直接取用如下

<%= render_board_name_path(@board) %>

什麼是 partial

Partial簡單說就是程式碼中的一小段,通常使用在HTML中讓View的Code可以更乾淨,將重複使用到的區塊切成獨立的Partial,比方說頁首頁尾、表單、社群插件等等,讓任何一個頁面都可以讀取這段Partial而不用重複寫一次一模一樣的Code。

假設我們常常需要在頁面產生topics的列表,就可以考慮將列表包裝成partial,這樣每個頁面需要時只要render這個partial就可以了。

_topic_list.html.erb
<ul>
<% @topics.each do |topic| %>
  <li># <%= topic.id %></li>
  <li>Topic Name: <%= link_to(topic.title, topic_path(topic)) %></li>
  <li>Description: <%= topic.content %></li>
<% end %>
</ul>

這樣頁面就會變得很簡單:

index.html.erb
...
<%= render "topic_list" %>
...

什麼是 collection partial

正常的Partial只會將內容Render出來一次,collection partial則會自動count我們給予的物件,並render count的次數,可以省去在Partial內再寫block或helper的繁瑣,讓partial更簡潔。
延續上一題的例子,我們可以改寫成:

_topic_list.html.erb
<li># <%= topic.id %></li>
<li>Topic Name: <%= link_to(topic.title, topic_path(topic)) %></li>
<li>Description: <%= topic.content %></li>

然後這樣render:

index.html.erb
...
<ul><%= render :partial => "topic_list", :collection => @topics, :as => :topic %></ul>
...

如此一來就不用在view裡面包block了。

什麼東西應該放在 partial / 什麼東西應該放在 helper

partial負責處理大片的html code,或是之後要利用ajax render出來的片段。
helper則負責處理跟邏輯判斷有關的東西,比方判斷文章發佈狀態或是讀取變數的值等等。

topics_helper.rb
module TopicsHelper
#需要邏輯判斷的工作留給helper

def render_published_topic_name_path(topic)
    link_to(topic.name, topic_path(topic))  if topic.is_published?
end
_topic_info.html.erb
#partial只需要負責html的部分
<table>
  <thead>
    <tr>
      <td>Topic name</td>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><%= render_published_topic_name_path(topic) %></td>
    </tr>
  </tbody>
<table>

yield in view

yield就是會被替換成樣板的地方,基本上所有的html.erb檔案最後就是顯示在<%= yield %>的地方,這樣做的好處是可以將網站的版型固定,只在需要出現內容的地方用yield引進來就可以了。
通常rails專案中都會有一個application.html.erb的檔案,我們的html.erb檔就是被引入這裡

application.html.erb
<!DOCTYPE html>
<html>
<head>
  ...
</head>
<body>
  <div class="container">
    # erb檔案就是被引入這裡
    <%= yield %>
  </div>
  #可以指定要yield哪個區塊
  <%= yield(:javascripts) %>
</body>
</html>

另外我們也可以指定要yield哪個區塊,我們可以用content_for的方式讓content替換掉<%= yield(:javascripts) %>

<%= content_for :javascripts do %>
    #content here
<% end %>

不應該放在 view 裡的東西

邏輯判斷

<% if topic.present? %>
    <%= @topic.title %>
<% else %>
    Unknown
<% end %>

ruby block

<% @topics.each do |topic| %>
    #content
<% end %>

撈Model資料的code

<%= Topic.find(params[:id]).title %>

form

Form表單是給使用者輸入資料的地方,預設是使用post方法送出資料,再由rails決定是新增或是修改。
Rails內最常見的表單helper就是form_for,可以幫我們針對特定model以及model內的欄位送出資料

<%= form_for @topic do |f| %>
    <%= f.label :name %>
    <%= f.text_field :name %>
    <%= f.submit %>
<% end %>

其中如label、text_field和submit也是form的helper,幫助產生對應的html tag。

essential helpers

必要的helper?

helper patterns

helper是以module的形態存在的,在rails內負責寫view要用到的method。
所以設計時能夠保持「簡單」且「可重副使用」是最重要的
通常我們要使用helper的時機是view有太多髒亂的code的時候,所以有時候會想把所有的髒code都寫進同一個helper method裡面,這是不對的。
比較好的做法是應該把這些髒code拆成很多不同的小部分,再針對不同的部分判斷是要放在partial還是helper。
我們也可以在partial內搭配helper,這也是讓view變乾淨的好方法。

由於要讓helper保持「簡單」且「可重副使用」,在設計helper時應該讓helper只「做一件事情」。
(例如:判斷是否能編輯文章、回傳文章的連結按鈕)
這樣做的好處是這個helper就會變得重複使用性很高(畢竟很多地方都需要判斷是否能編輯文章),就不會變成為了某個特定的view寫了一個helper卻只能用到一次,落實don't repeat your code的ruby精神。

以下一些常見的helper設計方法舉例:
1.儘量避免太多html code(無論ruby的或純html)
2.View裡面有太多讓人難以理解的判斷時,裝在helper裡面並語意命名,讓view更能理解

<% if current_user && current_user = @topic.user_id %>
    #show shomething
<% end %>

可以改成

<% if editable?(current_user) %>
    #show shomething

<% end %>

推薦參考文章:
http://blog.xdite.net/posts/2011/12/09/how-to-design-helpers
http://blog.xdite.net/posts/2011/12/10/how-to-design-helpers-2
http://blog.xdite.net/posts/2012/01/16/how-to-design-helper-3

← [Rails 高級新手系列] 關於Rails [Rails 高級新手系列] 關於MVC-什麼東西應該放在Controller →
 
comments powered by Disqus