Rendering microposts
我們計畫在使用者的資料頁面(show.html.erb)顯示使用者的 microposts,還要顯示使用者發佈了多少篇 microposts,你會發現很多做法會跟之前列出使用者的方法類似。(參考 Section 9.3)
雖然之後才會用到 controller,但因為馬上就會用到 view,所以先建立一個 controller:
$ rails generate controller Microposts
這節的主要目的就是要渲染使用者發布的所有 microposts,之前用過這樣的程式碼(參考 Section 9.3.5):
<ul class="users">
<%= render @users %>
</ul>
上述程式碼會自動使用 _user.html.erb partial 渲染 @user 變數中的每個使用者。我們要定義 _micropost.html.erb partial 使用相同的技巧來渲染 microposts 的集合(collection):
<ol class="microposts">
<%= render @microposts %>
</ol>
注意,我們使用了有序清單 ol,因為 microposts 是按照一定順序排列的。
完整的 partial 如下:
app/views/microposts/_micropost.html.erb
<li id="micropost-<%= micropost.id %>" class="clearfix">
<%= link_to gravatar_for(micropost.user, size: 50), micropost.user %>
<span class="user"><%= link_to micropost.user.name, micropost.user %></span>
<span class="content"><%= micropost.content %></span>
<span class="timestamp">
Posted <%= time_ago_in_words(micropost.created_at) %> ago.
</span>
</li>
這邊自己在
li加了一個 classclearfix,清除 float 造成的問題
這邊使用了 time_ago_in_words 輔助方法,這個方法的作用很明顯,之後會看到效果,另外也為每篇 micropost 定義了 CSS id:
<li id="micropost-<%= micropost.id %>">
因為說不定之後你會使用例如 JavaScript 處理單篇 micropost,因此指定 id 可以方便操縱元素。
接下來要解決顯示大量 microposts 的問題。我們可以使用在 Section 9.3.3 顯示大量使用者的方法來解決這個問題,也就是使用分頁。和之前一樣,使用的是 will_paginate 方法:
<%= will_paginate @microposts %>
如果和之前的 user 列表頁面比較,會發現使用的程式碼為:
<%= will_paginate %>
在 User controller 中,will_paginate 假設有一個 @user 實例變數存在(Section 9.3.3 提過,這個變數所屬的 class 是 ActiveRecord::Relation)。
而目前我們的情況是雖然還是在 User controller 裡,但我們要分頁顯示的是 microposts(而不是 users),所以我們要傳一個 @microposts 變數給 will_paginate 方法。
這表示我們必須在 user show action 定義一個 @microposts 的變數:
app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def show
@user = User.find(params[:id])
@microposts = @user.microposts.paginate(page: params[:page])
end
.
.
.
end
你會發現 paginate 很聰明,甚至可以在關聯上使用,從 microposts table 裡取出每一頁要顯示的 microposts。
最後,我們要顯示使用者發布多少篇 microposts,可以使用 count 方法:
user.microposts.count
跟 paginate 一樣,count 方法也可以在關聯上使用。count 並不會從資料庫裡取出所有 microposts 然後在取出結果的陣列上調用 length 方法,因為當 microposts 數量一多,會很沒有效率。
反之,count 會直接在資料庫裡做運算,讓資料庫計算指定的 user_id 擁有多少 microposts(所有資料庫都會對這種操作做性能優化,如果計算數量還是遇到性能瓶頸,可以使用 counter cache 來提高速度)。
現在就來把 microposts 加進個人資料頁面,注意我們使用 if @user.microposts.any 來確保使用者沒有 microposts 的話就不會顯示在頁面上:
app/views/users/show.html.erb
<% provide(:title, @user.name) %>
<div class="row">
<aside class="col-md-4">
<section class="user_info">
<h1>
<%= gravatar_for @user %>
<%= @user.name %>
</h1>
</section>
</aside>
<div class="col-md-8">
<% if @user.microposts.any? %>
<h3>Microposts (<%= @user.microposts.count %>)</h3>
<ol class="microposts">
<%= render @microposts %>
</ol>
<%= will_paginate @microposts %>
<% end %>
</div>
</div>
現在可以來看一下使用者的資料頁面,不過目前什麼都沒有,因為還沒建立任何 microposts:
