【Rilas】ページネーション機能の実装で勉強したこと。

一覧表示画面にページネーション機能をつけた際に勉強になった事を備忘録として残しています。
## 前提
ページネーション機能をつける前のビューなどです。
### コントローラー
事前にソート機能をつけています。

```ruby:app/controller/stocks_controller.rb
class StocksController < ApplicationController
  helper_method :sort_column, :sort_direction

  def index
    @calendar = Calendar.find(params[:calendar_id])
    @stocks = @calendar.stocks.order("#{sort_column} #{sort_direction}")
    @products = Product.all
  end

  private

  def sort_direction
    %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc'
  end

  def sort_column
    Stock.column_names.include?(params[:sort]) ? params[:sort] : 'id'
  end

end
```
### ヘルパーメソッド(追記)
大事なヘルパーメソッドの記述を抜かっておりました・・・。

```ruby:app/helper/stocks_helper.rb
module StocksHelper
  def sort_order(column, title)
    css_class = (column == sort_column) ? "current #{sort_direction}" : nil
    direction = (column == sort_column && sort_direction == 'asc') ? 'desc' : 'asc'
    link_to title, { sort: column, direction: direction }, class: "sort_header #{css_class}"
  end
end
```

### ビュー

```reb:app/views/stocks/index.html.erb
    <table>
      <thead>
        <tr>
          <th scope="col"><%= sort_order "display", "陳列" %></th>
          <th scope="col"><%= sort_order "publisher", "出版社名" %></th>
          <th scope="col"><%= sort_order "magazine_name", "雑誌名" %></th>
          <th scope="col"><%= sort_order "num", "冊数" %></th>
          <th scope="col"><%= sort_order "price", "本体価格" %></th>
          <th scope="col"><%= sort_order "i_form", "発行形態" %></th>
          <th scope="col"><%= sort_order "purchased", "買切雑誌" %></th>
        </tr>
      </thead>
      <tbody>
        <% @stocks.each do |stock| %>
          <% if stock.num > 0 %>
                <tr>
                  <td><%= stock.display %></td>
                  <td><%= stock.publisher %></td>
                  <td><%= stock.magazine_name %></td>
                  <td><%= stock.num %></td>
                  <td><%= stock.price.to_s(:delimited) %></td>
                  <td><%= stock.i_form %></td>
                  <td><%= stock.purchased %></td>
                </tr>
          <% end %>
        <% end %>
      </tbody>
    </table>
```

## ページネーションの実装
今回kaminariというページネーション用のgemを使って実装しました。
意外と簡単に実装できました〜。

### kaminariのインストール
Gemfileに`gem 'kaminari'`を追加し、`$ bundle install`でインストールします。

```ruby:Gemfile
gem 'kaminari'
```

gemをインストールした後は一度サーバを再起動しましょう。
`Ctrl-c `でサーバを止め、` rails s`でサーバを起動できます。
また、忘れてて右往左往しました・・・。

これでkaminariのインストールは完了です。

### ページネーションを表示させる
お次はcontrollerです。
ページネーションを表示させたいデータに`.page(params[:page])`を追加します。

```ruby:app/controllers/stocks_controller.rb
def index
  # ページネーションをつけたいデータに.page(params[:page])を追加
  @stocks = @calendar.stocks.page(params[:page]).order("#{sort_column} #{sort_direction}")
end
```
#### 余談(1.ページに表示するレコード数の変更)
1ページに表示するレコード数は初期値では25件なのだそうです。
controllerに`.per(表示したいレコード数)`を追加すると変更できるそうです。

例えば、30件表示したい場合は`.per(30)`と追加。

```ruby:app/controllers/stocks_controller.rb
def index
  # .per(30)を追加
  @stocks = @calendar.stocks.page(params[:page]).per(30).order("#{sort_column} #{sort_direction}")
end
```
って感じです。

最後に、viewでページネーションを表示させたいところへ
`<%= paginate @stocks %>`を追加します。

```reb:app/views/stocks/index.html.erb
    <%= paginate @stocks %>
    <table>
 〜〜　省略　〜〜
    </table>
```
#### 余談(2.表示を日本語に変更する)
ページ番号の前後についている`<<First`とか`<Prve`は判りづらいと感じたので
こちらを日本語に変更していきます。

```ruby:config/application.rb
#　〜〜省略〜〜
module Teiki29770(アプリ名です)
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.0

    # 日本語の言語設定
    config.i18n.default_locale = :ja
    config.time_zone = 'Tokyo'

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.
  end
end
```
サーバを再起動しましょう！
`config/locales`に日本語変換用のymlファイル`ja.yml`を作成して、
以下のコードを追加してみます。

```yml:config/locales/ja.yml
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: "次 &rsaquo;"
      truncate: "..."
```
これで表示を日本語に変更できました!やった！！
と、思っていたら・・・。
## 表示数にズレが出てしまう。
![スクリーンショット 2020-12-16 16.17.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/5ab2f010-bee2-4825-a986-47c47c7cb472.png)
なんか少ない・・・。30件表示できるはずなのに・・・。
調べてみると他のページも表示数はまちまちでした。
### ビューでの条件式が原因
コントローラーで指定している通り、30件づつデータを送って
ビューのほうで条件式に合うデータのみを表示していることが原因でした。

```erb:app/views/stocks/index.html.erb
 〜〜　省略　〜〜
      <tbody>
        <% @stocks.each do |stock| %>
          <% if stock.num > 0 %>⇦ここが原因。
                <tr>
                  <td><%= stock.display %></td>
                  <td><%= stock.publisher %></td>
                  <td><%= stock.magazine_name %></td>
                  <td><%= stock.num %></td>
                  <td><%= stock.price.to_s(:delimited) %></td>
                  <td><%= stock.i_form %></td>
                  <td><%= stock.purchased %></td>
                </tr>
          <% end %>
        <% end %>
      </tbody>
    </table>
```
なので、コントローラーの方で条件に合うデータだけを先に抽出しておいて
そちらを30件ずつビューへ送る様にします。

```ruby:app/controller/stocks_controller.rb

  def index
    @calendar = Calendar.find(params[:calendar_id])
    @stocks = @calendar.stocks.where("num > ?",0).page(params[:page]).per(30).order("#{sort_column} #{sort_direction}")

  end
```
```erb:app/views/stocks/index.html.erb
 〜〜　省略　〜〜
      <tbody>
        <% @stocks.each do |stock| %>
          〜〜　if文を削除　〜〜
                <tr>
                  <td><%= stock.display %></td>
                  <td><%= stock.publisher %></td>
                  <td><%= stock.magazine_name %></td>
                  <td><%= stock.num %></td>
                  <td><%= stock.price.to_s(:delimited) %></td>
                  <td><%= stock.i_form %></td>
                  <td><%= stock.purchased %></td>
                </tr>
        <% end %>
      </tbody>
    </table>
```
これで、しっかりと条件に沿ったデータを表示することができました！
![スクリーンショット 2020-12-16 18.33.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/927441/842ec9e4-a3fb-9252-0724-ed9ba0365f2e.png)
ちゃんとソートもできます！
### 勉強になったこと
MVCの関係性の大事さと共に、役割分担をしっかりとすることの大切さを再確認できました。
ありがとう、ページネーション！
## 参考にさせていただいたサイト様
https://qiita.com/rio_threehouse/items/313824b90a31268b0074
ありがとうございます！