[Rails]will_paginateで表示件数を選択できるページネーションを実装する

Railsでデータ表を表示する際、行数(データ数)が多い場合には当然ページが無駄に長くなってしまうため、ページ分割を行った方が良い。
ここではページネーションが簡単に実装できるGem「**will_paginate**」を紹介して、+αとしてドロップボタンによる表示件数選択も実装する。

# ページネーション
**ページ割り**のこと。一番馴染み深い例で言えば、Google検索のコレ。
<img width="334" alt="スクリーンショット 2018-07-17 23.56.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/43b7328f-2804-0af0-b63f-8f76f5b827e5.png">
ページにデータ表を作る際にn行ずつ表示させることで、よりスッキリしたデザインにできる。

# will_paginateによる実装
**book_list.html.erb**に、こんな感じの表を作成したとする。

<img width="1174" alt="スクリーンショット 2018-07-18 0.11.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/f8d58a28-ef2d-4102-8027-c7e0d5af1743.png">

12件一気に表示すると縦に長くなってしまうため、まずは５件ずつ表示するようにページネーションを実装する。

※参考
http://blog.otsukasatoshi.com/entry/2017/07/10/120000

まずはGemfileにwill_paginateを追加する

```Gemfile
gem 'will_paginate'
gem 'bootstrap-will_paginate'
```
will_paginateだけでもページネーションは実装できるが、見た目が圧倒的に良くなるのでbootstrap-will_paginateも追加する事を推奨する。

次に、Controllerを以下のように修正

```book_controller.rb
def book_list
   @books = Book.paginate(page: params[:page], per_page: 5)
end
```

will_paginateが導入されている時点で、各Modelにpaginateメソッドが追加される。
表示するデータがBookの全データだった場合は、.allが.paginateに置き換わるだけ。
**page:**は参照しているページ番号の事で、これは自動的に設定される値なのでそのままでOK。
**per_page:**は１ページに表示する件数。今回は5件ごとに表示するので5。

最後にViewに以下の２行を追加。

```erb:book_list.html.erb
<tbody class="text-center">
　<%= will_paginate @books, :previous_label => ' &lt 前へ', :next_label => '次へ &gt' %> # この行と
　　<% @books.each do |book| %>
　　　<tr>
　　　　<td><%= book.id %></td>
　　　　<td><%= book.title %></td>
　　　　　[...省略...]
　　　</tr>
　　<% end %>
</tbody>
<%= will_paginate @books, :previous_label => ' &lt 前へ', :next_label => '次へ &gt' %>　# この行を追記
```

これだけでページネーションの実装が完了する。will_paginateすごい。
Viewで追加する行は

```erb
<%= will_paginate @books %>
```
だけで十分であるが、defaultだと「前へ」「後ろへ」の表記が英語になってしまうため、上のコードでは少しいじってある。

実際に動かしてみたモノがこちら。
<img width="1201" alt="スクリーンショット 2018-07-18 0.30.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/97f4816a-0616-01a4-d335-7ea428aa8ea4.png">

Viewで挿入した位置に、ちゃんとボタンが追加されている。bootstrap-will_paginateのおかげで見た目も悪くない。

# 表示件数選択機能
上の例では5件ずつ表示したが、表示件数も弄れるようにした方が快適なので、ドロップダウンから設定できるようにする。
[will_paginate](https://github.com/mislav/will_paginate)のREADMEを見たところ、そういうドロップダウンボタンが用意されてる訳ではないようなので、自分で作成する。

ここでは"/book_list/:件数"に飛ばして、paramsからper_pageを設定することとする。
ただし、:pageはpaginateで予約されているため、パラメータ名は別の単語を使う(ここでは**:per**とする)

```route.rb
get "book_list/:per" => "book#book_list_page"
get "book_list" => "book#book_list"
```

``````book_controller.rb
def book_list
   @page = 5
   @books = Book.paginate(page: params[:page], per_page: @page)
end

def book_list_page
   @page = params[:per]
   @books = Book.paginate(page: params[:page], per_page: @page)
   render("book_list")
end
```

```erb:book_list.html.erb
<div class="dropdown">
　<button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
　　<%= @page %>
　　<span class="caret"></span>
　</button>
　<ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
　　<li><%= link_to("3", "/book_list/3") %></li>
　　<li><%= link_to("5", "/book_list/5") %></li>
　　<li><%= link_to("10", "/book_list/10") %></li>
　　<li><%= link_to("20", "/book_list/20") %></li>
　</ul>
　<label>件ずつ表示する</label>
</div>

<thead class="text-center">
[...省略...]
<tbody class="text-center">
　<%= will_paginate @books, :previous_label => ' &lt 前へ', :next_label => '次へ &gt' %>
　　<% @books.each do |book| %>
　　　<tr>
　　　　<td><%= book.id %></td>
　　　　<td><%= book.title %></td>
　　　　　[...省略...]
　　　</tr>
　　<% end %>
</tbody>
<%= will_paginate @books, :previous_label => ' &lt 前へ', :next_label => '次へ &gt' %>
[以下略]
```

これを実装した結果がこちら。
<img width="1197" alt="スクリーンショット 2018-07-18 0.52.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/197878/ad508d15-28e1-d32d-4980-29c911779538.png">
左上のドロップダウンから表示件数が選択でき、表示件数を変えるたびにページ数も変化する。

# まとめ
will_paginateで簡単にページネーションが実装できた。
表示件数を設定するボタンも実装することができた。