紙一重の積み重ね

アラフォーのエンジニアがなれる最高の自分を目指して、学んだことをこつこつ情報発信するブログです。

【10章】Ruby on Railsチュートリアル演習まとめ&解答例【10.3 すべてのユーザーを表示する】

はじめに

Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版の 10章 10.3 すべてのユーザーを表示するの演習まとめ&解答例です。

個人の解答例なので、誤りがあればご指摘ください。

動作環境

  • cloud9
  • ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
  • Rails 5.0.0.1

10.3.1 ユーザーの一覧ページ

本章での学び

テストコードの作成

indexアクションに対するテストコードを作成する。

yokoyan:~/workspace/sample_app (updating-users) $ rails routes
   Prefix Verb   URI Pattern               Controller#Action
    login GET    /login(.:format)          sessions#new
          POST   /login(.:format)          sessions#create
    users GET    /users(.:format)          users#index
          POST   /users(.:format)          users#create
  • usert_pathにGETリクエストでアクセスする
  • login_urlにリダイレクトされること
  test "should redirect index when not logged in" do
    get users_path
    assert_redirected_to login_url
  end

【filter】beforeフィルターの修正

beforeフィルターに、indexアクションを追加する。

class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update]

【controller】indexアクションの作成

すべてのユーザー情報を表示するために、indexアクション内でUser.allメソッドを呼び出す。 データベースから取得したすべてのユーザー情報を、インスタンス変数@usersに格納する。

  def index
    @users = User.all
  end

【View】indexビューの作成

indexアクションで取得した@usersの中身を、@users.each do |user|で1件ずつ取り出す。

<% provide(:title, 'All users')%>
<h1>All users</h1>

<ur class="users">
  <% @users.each do |user| %>
    <li>
      <% gravatar_for_user, size:50 %>
      <% link_to user.name, user %>
    </li>
  <% end %>
</ur>

【css】indexページ用のscssの作成

カスタムscssに、indexビューで使用するusersクラスを定義する。

.users {
  list-style: none;
  margin: 0;
  li {
    overflow: auto;
    padding: 10px 0;
    border-bottom: 1px solid $gray-lighter;
  }
}

【view】ヘッダーにindexページヘのリンクを追加する

これまで、#となっていた箇所を実装する。

<li><%= link_to "Users", users_path %></li>

動作確認

ブラウザで確認。 image.png

テストコードがgreenになることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails test
Running via Spring preloader in process 2279
Started with run options --seed 60667

  36/36: [===============================================================================================================================================================================================] 100% Time: 00:00:06, Time: 00:00:06

Finished in 6.97019s
36 tests, 101 assertions, 0 failures, 0 errors, 0 skips

演習1

レイアウトにあるすべてのリンクに対して統合テストを書いてみましょう。ログイン済みユーザーとそうでないユーザーのそれぞれに対して、正しい振る舞いを考えてください。ヒント: log_in_asヘルパーを使ってリスト 5.32にテストを追加してみましょう。

site_layout_test.rbにテストを追加する。

  • 未ログインユーザーの場合
    • home
    • help
    • about
    • contact
    • News(静的URLのため対象外とする)
  • ログイン済みユーザーの場合
    • home
    • help
    • Users
    • Account
      • Profile
      • Settings
      • Log out
    • about
    • contact
    • News(静的URLのため対象外とする)
  test "layout links" do
    get root_path
    assert_template 'static_pages/home'
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
    assert_select "a[href=?]", login_path
    get contact_path
    assert_select "title", full_title("Contact")
    get signup_path
    assert_select "title", full_title("Sign up")
  end
  
  test "layout links when logged in user" do
    log_in_as(@user)
    get root_path
    assert_select "a[href=?]", root_path, count:2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
    assert_select "a[href=?]", users_path
    assert_select "a[href=?]", user_path(@user)
    assert_select "a[href=?]", edit_user_path(@user)
    assert_select "a[href=?]", logout_path
  end

10.3.2 サンプルのユーザー

本章での学び

Rubyを使って、一気にユーザーを作成する。

faker gemのインストール

事前準備として、fakerをインストールする。

gem 'faker',  '1.6.6'
bundle install

Railsタスク(Rubyスクリプト)の生成

  • db/seeds.rbにRubyスクリプトを生成する
    • Example Userを1人作成する
    • fakerで、それらしい名前を持つユーザを99人生成する
User.create!( name:   "Example User",
              email:  "example@railstutorial.org",
              password: "foobar",
              password_confirmation: "foobar" )

99.times do |n|
  name = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  password = "password"
  User.create!( name:   name,
                email:  email,
                password: password,
                password_confirmation: password )
end

Railsタスクの実行

以下を実行する。

rails db:migrate:reset
rails db:seed

ブラウザからUsersメニューを選択すると、ユーザが100人に増えている!すごい!! image.png

演習1

試しに他人の編集ページにアクセスしてみて、10.2.2で実装したようにリダイレクトされるかどうかを確かめてみましょう。

Example Userでログインしている状態で、猫アイコンのユーザ(id=5)にアクセス。 image.png

image.png

URLに「https://xxxxx/users/5/edit」でアクセスすると、TOPページにリダイレクトされることを確認。 image.png

10.3.3 ページネーション

本章での学び

100人のユーザに対して、1ぺージ30人ずつ表示するページネーションを追加する。

ページネーションメソッド(will paginate)のインストール

gemでwill_paginateと、bootstrap-will_paginateをインストールする。

gem 'will_paginate',  '3.1.0'
gem 'bootstrap-will_paginate',  '0.0.10'
bundle install

インストールしたら、WEBサーバを再起動する。

【view】indexページでpaginateを使う

リストの上下に、<%= will_paginate %>を追加する。 理由は、ページの上下にページネーションを表示するため。

<%= will_paginate %>

<ul class="users">
  <% @users.each do |user| %>
    <li>
      <%= gravatar_for user, size: 50 %>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>

<%= will_paginate %>

ページ上部のページネーション。 image.png

ページ下部のページネーション。 image.png

【controller】ユーザー情報をpaginateに格納する

User.allを、User.paginateに置き換える。 paginateメソッドは、Usersテーブルから30件取得した結果を格納している。

yokoyan:~/workspace/sample_app (updating-users) $ rails console
Running via Spring preloader in process 2489
Loading development environment (Rails 5.0.0.1)
>> User.paginate(page:1 )
  User Load (2.2ms)  SELECT  "users".* FROM "users" LIMIT ? OFFSET ?  [["LIMIT", 30], ["OFFSET", 0]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-06-13 03:57:28", updated_at: "2017-06-13 03:57:28", password_digest: "$2a$10$zGDH/dBloZT0Txbp62FHdO13Mt16cBWhQehUmwKcY4l...", remember_digest: nil>, #<User id: 2, name: "Myrl West", email: "example-1@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$.1qwJtz9AnqDvkRfV9MYAetPEQP1dvl1EkVDGZ.HzTP...", remember_digest: nil>, #<User id: 3, name: "Rodger Simonis", email: "example-2@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$BNzrCTPh.vPCbCo5L.JZ6eiaUxTQgvRT5y40sHjgYSF...", remember_digest: nil>, #<User id: 4, name: "Cecelia Adams", email: "example-3@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$j9SIW6g6ASDW8j38XqNYtu/zsx2Y6Q43Smup7.uwSGW...", remember_digest: nil>, #<User id: 5, name: "Torey Schmitt", email: "example-4@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$Lp8fRB0eUc0IFvBg6/xF6uMQg5eW2SXH7hP2Zggk6LM...", remember_digest: nil>, #<User id: 6, name: "Jorge Luettgen PhD", email: "example-5@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$KPIuq2hPkHBsjeS7uG5X.u3LFz1j5PV.mjrAc4ht9w6...", remember_digest: nil>, #<User id: 7, name: "Eriberto Littel DVM", email: "example-6@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$f8n9xlsWJXEdUUaWrNi6zeu4MwXSASplByQazMGj6Q4...", remember_digest: nil>, #<User id: 8, name: "Kelley Bode", email: "example-7@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$SNwYoPOY5xtpmA6PkJ5wM.k7NycvFUrnUKZz2nDQedW...", remember_digest: nil>, #<User id: 9, name: "Jakob Muller", email: "example-8@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$y6UTasDZYRzfoet.TG9wbO9dyQkiq1bkoleLhxMK6aE...", remember_digest: nil>, #<User id: 10, name: "Jean Franecki", email: "example-9@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$A43xSShhuOePJ39KKQ3VWuzuq1oTkL25K2RG1t4.R8Q...", remember_digest: nil>, ...]>

実装する。 page:パラメータのparams[:page]は、will_paginateによって自動的に生成して代入される。

  def index
    # @users = User.all
    @users = User.paginate(page: params[:page])
  end

演習1

Railsコンソールを開き、pageオプションにnilをセットして実行すると、1ページ目のユーザーが取得できることを確認してみましょう。

nilの場合、1ページ目のユーザーが取得できることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails console
Running via Spring preloader in process 2221
Loading development environment (Rails 5.0.0.1)
>> User.paginate(page: nil)
  User Load (10.0ms)  SELECT  "users".* FROM "users" LIMIT ? OFFSET ?  [["LIMIT", 30], ["OFFSET", 0]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-06-13 03:57:28", updated_at: "2017-06-13 03:57:28", password_digest: "$2a$10$zGDH/dBloZT0Txbp62FHdO13Mt16cBWhQehUmwKcY4l...", remember_digest: nil>, #<User id: 2, name: "Myrl West", email: "example-1@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$.1qwJtz9AnqDvkRfV9MYAetPEQP1dvl1EkVDGZ.HzTP...", remember_digest: nil>, #<User id: 3, name: "Rodger Simonis", email: "example-2@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$BNzrCTPh.vPCbCo5L.JZ6eiaUxTQgvRT5y40sHjgYSF...", remember_digest: nil>, #<User id: 4, name: "Cecelia Adams", email: "example-3@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$j9SIW6g6ASDW8j38XqNYtu/zsx2Y6Q43Smup7.uwSGW...", remember_digest: nil>, #<User id: 5, name: "Torey Schmitt", email: "example-4@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$Lp8fRB0eUc0IFvBg6/xF6uMQg5eW2SXH7hP2Zggk6LM...", remember_digest: nil>, #<User id: 6, name: "Jorge Luettgen PhD", email: "example-5@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$KPIuq2hPkHBsjeS7uG5X.u3LFz1j5PV.mjrAc4ht9w6...", remember_digest: nil>, #<User id: 7, name: "Eriberto Littel DVM", email: "example-6@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$f8n9xlsWJXEdUUaWrNi6zeu4MwXSASplByQazMGj6Q4...", remember_digest: nil>, #<User id: 8, name: "Kelley Bode", email: "example-7@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$SNwYoPOY5xtpmA6PkJ5wM.k7NycvFUrnUKZz2nDQedW...", remember_digest: nil>, #<User id: 9, name: "Jakob Muller", email: "example-8@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$y6UTasDZYRzfoet.TG9wbO9dyQkiq1bkoleLhxMK6aE...", remember_digest: nil>, #<User id: 10, name: "Jean Franecki", email: "example-9@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$A43xSShhuOePJ39KKQ3VWuzuq1oTkL25K2RG1t4.R8Q...", remember_digest: nil>, ...]>
>> 

演習2

先ほどの演習課題で取得したpaginationオブジェクトは、何クラスでしょうか? また、User.allのクラスとどこが違うでしょうか? 比較してみてください。

どちらのクラスも、User::ActiveRecord_Relationであるため同じクラス。

User.paginateで取得した結果を変数pageに格納する。 User.paginateのクラスは、User::ActiveRecord_Relation

?> page = User.paginate(page: nil)
  User Load (0.4ms)  SELECT  "users".* FROM "users" LIMIT ? OFFSET ?  [["LIMIT", 30], ["OFFSET", 0]]
=> #<ActiveRecord::Relation [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-06-13 03:57:28", updated_at: "2017-06-13 03:57:28", password_digest: "$2a$10$zGDH/dBloZT0Txbp62FHdO13Mt16cBWhQehUmwKcY4l...", remember_digest: nil>, #<User id: 2, name: "Myrl West", email: "example-1@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$.1qwJtz9AnqDvkRfV9MYAetPEQP1dvl1EkVDGZ.HzTP...", remember_digest: nil>, #<User id: 3, name: "Rodger Simonis", email: "example-2@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$BNzrCTPh.vPCbCo5L.JZ6eiaUxTQgvRT5y40sHjgYSF...", remember_digest: nil>, #<User id: 4, name: "Cecelia Adams", email: "example-3@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$j9SIW6g6ASDW8j38XqNYtu/zsx2Y6Q43Smup7.uwSGW...", remember_digest: nil>, #<User id: 5, name: "Torey Schmitt", email: "example-4@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$Lp8fRB0eUc0IFvBg6/xF6uMQg5eW2SXH7hP2Zggk6LM...", remember_digest: nil>, #<User id: 6, name: "Jorge Luettgen PhD", email: "example-5@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$KPIuq2hPkHBsjeS7uG5X.u3LFz1j5PV.mjrAc4ht9w6...", remember_digest: nil>, #<User id: 7, name: "Eriberto Littel DVM", email: "example-6@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$f8n9xlsWJXEdUUaWrNi6zeu4MwXSASplByQazMGj6Q4...", remember_digest: nil>, #<User id: 8, name: "Kelley Bode", email: "example-7@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$SNwYoPOY5xtpmA6PkJ5wM.k7NycvFUrnUKZz2nDQedW...", remember_digest: nil>, #<User id: 9, name: "Jakob Muller", email: "example-8@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$y6UTasDZYRzfoet.TG9wbO9dyQkiq1bkoleLhxMK6aE...", remember_digest: nil>, #<User id: 10, name: "Jean Franecki", email: "example-9@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$A43xSShhuOePJ39KKQ3VWuzuq1oTkL25K2RG1t4.R8Q...", remember_digest: nil>, ...]>
>> 
?> page.class
=> User::ActiveRecord_Relation

User.allで取得した結果を変数page_allに格納する。 User.allのクラスは、User::ActiveRecord_Relation

?> page_all = User.all
  User Load (0.7ms)  SELECT "users".* FROM "users"
=> #<ActiveRecord::Relation [#<User id: 1, name: "Example User", email: "example@railstutorial.org", created_at: "2017-06-13 03:57:28", updated_at: "2017-06-13 03:57:28", password_digest: "$2a$10$zGDH/dBloZT0Txbp62FHdO13Mt16cBWhQehUmwKcY4l...", remember_digest: nil>, #<User id: 2, name: "Myrl West", email: "example-1@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$.1qwJtz9AnqDvkRfV9MYAetPEQP1dvl1EkVDGZ.HzTP...", remember_digest: nil>, #<User id: 3, name: "Rodger Simonis", email: "example-2@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$BNzrCTPh.vPCbCo5L.JZ6eiaUxTQgvRT5y40sHjgYSF...", remember_digest: nil>, #<User id: 4, name: "Cecelia Adams", email: "example-3@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$j9SIW6g6ASDW8j38XqNYtu/zsx2Y6Q43Smup7.uwSGW...", remember_digest: nil>, #<User id: 5, name: "Torey Schmitt", email: "example-4@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$Lp8fRB0eUc0IFvBg6/xF6uMQg5eW2SXH7hP2Zggk6LM...", remember_digest: nil>, #<User id: 6, name: "Jorge Luettgen PhD", email: "example-5@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$KPIuq2hPkHBsjeS7uG5X.u3LFz1j5PV.mjrAc4ht9w6...", remember_digest: nil>, #<User id: 7, name: "Eriberto Littel DVM", email: "example-6@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$f8n9xlsWJXEdUUaWrNi6zeu4MwXSASplByQazMGj6Q4...", remember_digest: nil>, #<User id: 8, name: "Kelley Bode", email: "example-7@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$SNwYoPOY5xtpmA6PkJ5wM.k7NycvFUrnUKZz2nDQedW...", remember_digest: nil>, #<User id: 9, name: "Jakob Muller", email: "example-8@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$y6UTasDZYRzfoet.TG9wbO9dyQkiq1bkoleLhxMK6aE...", remember_digest: nil>, #<User id: 10, name: "Jean Franecki", email: "example-9@railstutorial.org", created_at: "2017-06-13 03:57:29", updated_at: "2017-06-13 03:57:29", password_digest: "$2a$10$A43xSShhuOePJ39KKQ3VWuzuq1oTkL25K2RG1t4.R8Q...", remember_digest: nil>, ...]>
>> 
?> page_all.class
=> User::ActiveRecord_Relation

10.3.4 ユーザー一覧のテスト

本章での学び

paginateに対するテストを作成する。

【fixture】テストユーザを30人一気に追加する

埋め込みRubyを使って、30回繰り返す。

<% 30.times do |n| %>
user_<%= n %>:
  name: <%= "User #{n}" %>
  email: <%= "user-#{n}@example.com" %>
  password_digest: <%= User.digest('password')%>
<% end %>

【test】統合テストの作成

rails generateコマンドで自動生成する。

yokoyan:~/workspace/sample_app (updating-users) $ rails generate integration_test users_index
Running via Spring preloader in process 2260
Expected string default value for '--jbuilder'; got true (boolean)
      invoke  test_unit
      create    test/integration/users_index_test.rb

【test】テストコードの実装

  • ログインする
  • usersコントローラのindexアクションにGETリクエストを送信する(users_path)
  • インデックス画面のテンプレートが表示されることを確認
  • paginationクラスを持つdivタグが存在することを確認
  • 1ページ目にユーザーが存在することを確認

上記を踏まえ、実装する。

  test "index including pagination" do
    log_in_as(@user)
    get users_path
    assert_template 'users/index'
    assert_select 'div.pagination'
    User.paginate(page: 1).each do |user|
      assert_select 'a[href=?]', user_path(user), text: user.name
    end
  end

testがgreenになることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails test
Running via Spring preloader in process 2578
Started with run options --seed 20647

  38/38: [===============================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.88566s
38 tests, 142 assertions, 0 failures, 0 errors, 0 skips

演習1

試しにリスト 10.45にあるページネーションのリンク (will_paginateの部分) を2つともコメントアウトしてみて、リスト 10.48のテストが redに変わるかどうか確かめてみましょう。

<% #= will_paginate %>
・・・略・・・
<% #= will_paginate %>

テストがredになることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails test
Running via Spring preloader in process 2684
Started with run options --seed 62689

 FAIL["test_index_including_pagination", UsersIndexTest, 1.3556210420210846]
 test_index_including_pagination#UsersIndexTest (1.36s)
        Expected at least 1 element matching "div.pagination", found 0..
        Expected 0 to be >= 1.
        test/integration/users_index_test.rb:16:in `block in <class:UsersIndexTest>'

  38/38: [===============================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.74196s
38 tests, 112 assertions, 1 failures, 0 errors, 0 skips

演習2

先ほどは2つともコメントアウトしましたが、1つだけコメントアウトした場合、テストが greenのままであることを確認してみましょう。will_paginateのリンクが2つとも存在していることをテストしたい場合は、どのようなテストを追加すれば良いでしょうか? ヒント: 表 5.2を参考にして、数をカウントするテストを追加してみましょう。

1つだけコメントアウトする。

<% #= will_paginate %>
・・・略・・・
<%= will_paginate %>

テストがgreenになることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails test
Running via Spring preloader in process 2468
Started with run options --seed 50744

  38/38: [===================================================================================================================================================================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.01556s
38 tests, 142 assertions, 0 failures, 0 errors, 0 skips

will_paginateのリンクを2つカウントするためには、count: 2を追加する。

    assert_select 'div.pagination', count: 2

10.3.5 パーシャルのリファクタリング

本章での学び

動きは変えずに、より効率的なコードにリファクタリングを行う。

【view】indexビューのリファクタリング

<li>以下をrenderに変更する。

<ul class="users">
  <% @users.each do |user| %>
    <li>
      <%= gravatar_for user, size: 50 %>
      <%= link_to user.name, user %>
    </li>
  <% end %>
</ul>

修正後。

<ul class="users">
  <% @users.each do |user| %>
    <%= render user %>
  <% end %>
</ul>

【view】_userパーシャルの作成

render userで呼び出される、_user.html.erbを作成する。 パーシャルは、物理ファイルだけでなく、Userクラスのuser変数に対しても使用できる。

    <li>
      <%= gravatar_for user, size: 50 %>
      <%= link_to user.name, user %>
    </li>

この時点でアプリケーションをブラウザで確認すると、ユーザー一覧の表示はできる。 image

【view】indexページの完全なリファクタリング

@users.each do |user|の部分を排除して、renderを、@users変数に対して直接実行する。 Railsが自動的に、@usersが、Userオブジェクトのリストであると推測する。 さらに、自動的にそれぞれのユーザー情報を、_user.html.erbパーシャルで出力する。

リファクタリング前のソース。

<ul class="users">
  <% @users.each do |user| %>
    <%= render @user %>
  <% end %>
</ul>

完全なリファクタリング後のソース

<ul class="users">
  <%= render @users %>
</ul>

演習1

リスト 10.52にあるrenderの行をコメントアウトし、テストの結果が redに変わることを確認してみましょう。

該当箇所をコメントアウトする。

<ul class="users">
  <% #= render @users %>
</ul>

テストがredになることを確認。

yokoyan:~/workspace/sample_app (updating-users) $ rails test
Running via Spring preloader in process 2268
Started with run options --seed 34372

 FAIL["test_index_including_pagination", UsersIndexTest, 1.2261453189421445]
 test_index_including_pagination#UsersIndexTest (1.23s)
        Expected at least 1 element matching "a[href="/users/14035331"]", found 0..
        Expected 0 to be >= 1.
        test/integration/users_index_test.rb:18:in `block (2 levels) in <class:UsersIndexTest>'
        test/integration/users_index_test.rb:17:in `block in <class:UsersIndexTest>'

  38/38: [===============================================================================================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.74507s
38 tests, 113 assertions, 1 failures, 0 errors, 0 skips

おわりに

ユーザー一覧画面が完成しました。 Faker gemで100人のデータを生成して、will_paginate gemとパーシャルを使うことで、 ページ送り処理が簡単に実装することができました。 gemを組み合わせていくだけでWEBアプリケーションができるのはすごいです。 Railsチュートリアルが終わったら、他にどんなgemがあるのか組み込んでみたいと思います。