【Rails6.1】kaminariを使ったページネーションのレイアウトとか

# はじめに
GemのkaminariとBootstrapを使って、ページネーションのレイアウトを考えてみました。
レイアウト自体はほとんど参考記事をそのまま使ったような形になります。
それにプラスして<b>件数</b>を表示したかったのと、コントローラからデータを渡すときに躓きがちな<b>データの呼び出し方</b>についても一緒にまとめていきます。

ちなみに私の作業環境では、
Rails 6.1
Bootstrap5.3
を使用しています。

# 手順
私が作りたかったのはこんな感じのページネーションです。
これを作ったときの流れをお話します。

![2024-06-06ページネーション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3762011/86197b60-89c1-679a-f56f-e4f1af580d93.png)

## Bootstrapを使う
kaminariにBootstrapを適応する際、参考にさせていただいた記事がこちら。

https://qiita.com/rio_threehouse/items/313824b90a31268b0074

アプリケーションのビューにkaminariのフォルダを作成して、CSSからレイアウトの設定を書き換えています。
ここからはBootstrapや必要なビューなどは揃っている前提で進めます。

## CSSの記述
実際にSCSSに記述した内容がこちら。
ほとんど先ほどの記事をそのまま使わせていただき、色やborderの丸みを少し変えた状態になっています。

```css:scss
.paginate{
    margin: -10px 0;
}

.pagination>li>a {
    border: none;
    color: #696969;
    font-weight: normal;
}

.pagination>.active>a {
    background: #D8D8D8;
    border-radius: 5px;
    font-weight: normal;
}

.pagination>li>a:hover {
    border-radius: 5px;
}
```

## 日本語に変換
こちらも同じように記事を参考にさせていただき、Font Awesomeを使用しています。
参考記事とやっていることはほとんど同じです。
```css:config/locales/ja.yml
  ja:
    views:
      pagination:
        first: <i class="fas fa-angle-double-left"></i>
        last: <i class="fas fa-angle-double-right"></i>
        previous: <i class="fas fa-angle-left"></i> 前の12件
        next: 次の12件 <i class="fas fa-angle-right"></i>
        truncate: "..."
```

## ビューの記述
ビューでは<b>部分テンプレート</b>にしておくと、呼び出し部分で@&#8203;itemsや@&#8203;reviewsのように変数を書き換えることで同じようにページネーションを使用することが出来ます。

商品、レビュー、など、データさえ渡せればページネーション自体は書き換えなくていいので、これが地味に助かりました。
```html:部分テンプレートの呼び出し例
<%= render 'layouts/paginate', content: @items %>
```

```html:部分テンプレート
<hr>
<div class="paginate d-flex align-items-center justify-content-center flex-wrap-reverse">
  <small class="paginate-total text-center">
    <%= (content.current_page - 1) * content.limit_value + 1 %>件～<%= [content.current_page * content.limit_value, content.total_count].min %>件（全<%= content.total_count %>件）
  </small>
  <div class="pt-2 ps-2"><%= paginate content, theme: 'bootstrap-5' %></div>
</div>
<hr>
```

部分テンプレートのsmallタグの中には、
<b>「例）13件～24件（全25件）」</b>という数が表示できるようにしています。

<b>「(content.current_page - 1) * content.limit_value + 1」</b>では現在のページの開始件数を計算しています。
たとえば、1ページに12件表示する設定で現在が2ページ目なら、<b>(2 - 1) * 12 + 1で13</b>。

<b>「[content.current_page * content.limit_value, content.total_count].min」</b>では現在のページの終了件数を計算して、尚且つ全ての数を超えないようにしています。
たとえば、<b>全ての件数が25件で現在が2ページ目なら、終了件数は24</b>。

<b>「content.total_count」</b>は<b>全ての件数</b>です。

ちなみに私には少し難しかったので、チャットGPTに協力してもらいながら作っています。



# おまけ…kaminariのエラー
kaminariのページネーションは、基本的に.page(params[:page])を使用して呼び出すのですが、データの呼び出し方によっては上手く表示できなくなってしまう場合があります。

例えば、
```ruby:データが渡せない記述
@shop = current_shop
@shop_items = Item.where(shop_id: @shop.id)
@pre_orders = PreOrder.where(item_id: @shop_items.pluck(:id))
@visit_or_cancel_pre_orders = @pre_orders.where(status: 'visit') + @pre_orders.where(status: 'cancel').order(visit_day: "DESC").page(params[:page])
```
この書き方だと、後半の並び替えやページネーションのメソッドを付けなければデータが表示出来たけど、ページネーションを導入しようと思って.order(visit_day: "DESC").page(params[:page])を付けるとエラーになってしまいます。

これを書いていた当時は、どうして？と疑問でいっぱいでしたが、今見ると明らかにおかしいことが分かります。

そして、メンターの方に確認して修正してもらった記述がこちらです。
```diff_ruby:直してもらった方
@shop = current_shop
@shop_items = Item.where(shop_id: @shop.id)
@pre_orders = PreOrder.where(item_id: @shop_items.pluck(:id))
- @visit_or_cancel_pre_orders = @pre_orders.where(status: 'visit') + @pre_orders.where(status: 'cancel').order(visit_day: "DESC").page(params[:page])
+ @visit_or_cancel_pre_orders = @pre_orders.where(status: ['visit', 'cancel']).order(visit_day: "DESC").page(params[:page])
```
キレイにまとめる方法を教えていただきました。

そもそも+を使うのは基本的に配列の場合で、呼び出せてはいたものの一般的な記述方ではなかったようです。

## データの呼び出し方について
どうして.orderや.pageの使えないデータがあるのか疑問に思っていたのですが、そもそもデータの渡し方が違うようです。

https://qiita.com/kichion/items/a1539fcb124b69c765bf

.whereや.orderはrailsのモデルに指定してActiveRecord::Relationを返してくれるメソッドで、どうやら、pageもkaminariが用意したActiveRecord::Relationを返してくれるメソッドのようです。

そのため、データが配列の状態で送られていると、この.pageも同じように使えなくなってエラーが表示されます。
そんなときの救済措置もkaminariが用意してくれていました。

https://qiita.com/ten__/items/4f1b4d1e4fde3bb004a4

私は検索機能を作成した際にデータが配列になっていたのでKaminari.paginate_arrayを使いました。

このデータの違いについて知る前は、なんとなくモデル以外に使えない.whereや.orderに似た.pageメソッド。みたいなイメージしかなかったところ、理屈が分かってスッキリしました…！

# おわりに
先月の自分が分かっていなかった記述も、今月の自分が見たら明らかに間違っていると判断できるようになっていることに気づきました。
まだまだ、なんとなくで認識している部分がたくさんあるので、理屈が分かるように深掘りしていきたいです。