【Rails】ユーザー一覧の表示とページネーション【Rails Tutorial 10章まとめ】

##ユーザー一覧ページ
###indexアクションの認可
ユーザー一覧を表示するindexアクションとビューはログインユーザーにのみ表示したいので、logged_in_userを設定する。

```app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :logged_in_user, only: [:index, :edit, :update]
  before_action :correct_user,   only: [:edit, :update]

  def index
    @users = User.all
  end
  .
  .
  .
end
```
indexアクションには@users変数に全てのUserオブジェクトを入れておく。

テストを書く。

```test/controllers/users_controller_test.rb
  test "should redirect index when not logged in" do
    get users_path
    assert_redirected_to login_url
  end
```

###indexビュー
ユーザー一覧ページ用のindexビューを作成する。

```app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

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

ヘッダーにユーザー一覧ページへのリンクを貼っておく。

```erb:app/views/layouts/_header.html.erb
 <% if logged_in? %>
          <li><%= link_to "Users", users_path %></li>
          <li class="dropdown">
  .
  .
  .
```

###サンプルユーザーの生成
ユーザー一覧に表示するサンプルユーザーを手作業で作っていると手間なので、fakerジェムを使ってユーザーを大量生成する。

Gemfileにfakerジェムを追加する。

```rb:Gemfile
gem 'faker', '1.7.3'
```

seedファイルにユーザーを生成するRailsスクリプト（Railsタスク）を書く。

```db/seeds.rb
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
```
create!メソッドはcreateメソッドと違い、ユーザーが無効な場合でも例外を返すため、余計なエラーの現にならずに済む。

データベースのリセットと、Railsタスクの実行を行う。

```console
rails db:migrate:reset
rails db:seed
```

エラーを吐く場合はローカルサーバーを止めたりしてみる。
（自分の場合はseedファイルにデフォルトで入っていたコメントを残していたらエラーを吐いた。）

##ページネーション
###will_paginateメソッド
一つのページに表示するユーザーを３０人までとして、それ以降はページを切り替えて表示するページネーションを実装する。
まずGemfileにwill_paginateジェムとbootstrap-will_paginateジェムを追加する。

```rb:Gemfile
gem 'will_paginate',           '3.1.6'
gem 'bootstrap-will_paginate', '1.0.0'
```

ページネーションを実装するには、まずindexビューのユーザー表示部分をwill_paginateメソッドで挟む。

```erb:app/views/users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= 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 %>
```

次に、indexアクションの@users = User.allをUser.paginate(page: params[:page])に変える。

```app/controllers/users_controller.rb
  def index
    @users = User.paginate(page: params[:page])
  end
```
paginateメソッドは、:pageパラメータが１であれば１−３０のユーザーを、２であれば３１−６０のユーザーを取り出す（３０人ずつ取り出す設定にしている場合）。

ここでエラーを吐く場合は、will_paginateジェムのバージョンを上げてみるとよい。

##ユーザー一覧ページのテスト
###テスト用ユーザーの生成
fixtureファイルに、テスト用ユーザーを大量生成するRailsタスクを書く。

```test/fixtures/users.yml
michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>

archer:
  name: Sterling Archer
  email: duchess@example.gov
  password_digest: <%= User.digest('password') %>

lana:
  name: Lana Kane
  email: hands@example.gov
  password_digest: <%= User.digest('password') %>

malory:
  name: Malory Archer
  email: boss@example.gov
  password_digest: <%= User.digest('password') %>

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

###テスト
ユーザー一覧ページ用の統合テストを作成する。

```console
$ rails generate integration_test users_index
```

paginationクラスを持ったdivタグをチェックして、最初のページにユーザーがいることを確認する。

```test/integration/users_index_test.rb
require 'test_helper'

class UsersIndexTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:michael)
  end

  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
end
```

テストでは１ページ目に表示されるユーザーの名前が、各ユーザーのプロフィールページにリンクしていることを確認している。

##ユーザー一覧ページのパーシャル
割愛する。