PagyとTurbo Framesで手動無限スクロールをセットアップするための完全ガイド


最近仕事で、pagyを使ってボタンを押すたびに情報が出力される手動の無限スクロールを実装する際に苦労したので同じように苦労している方のために説明したいと思います。
# 参考にした実装
https://www.colby.so/posts/pagination-and-infinite-scrolling-with-hotwire

# 完成デザイン
![スクリーンショット 2024-09-16 22.45.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524128/423f0358-9fcc-87ca-c85d-ae575863cf71.png)
moreボタンを押下すると表示が増え、取得した情報がなくなるとボタンも消えます。
![スクリーンショット 2024-09-16 21.26.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3524128/af72ecf0-9047-1c28-2ad6-1376becf6f7d.png)

# 環境
- Ruby 3.2.2
- Rails 7.1.3.4
- gem
    - turbo-rails
    - pagy
- viewの拡張子はhaml

# pagyのセットアップ
### gemのインストール
pagyというページネーション用のGemがあるので、インストールします。

```rb:.Gemfile
gem 'pagy'
gem 'turbo-rails'
```
```
bundle install
```
### Controller
Controller側では```application_controller.rb``` に以下を追記します。

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include Pagy::Backend  #追記
end
```
### helper
```app/helpers/application_helper.rb```に以下を追記します。

```rb:app/helpers/application_helper.rb
module ApplicationHelper
  include Pagy::Frontend #追記
end
```

これでスクロールを実装する準備が整ったので実装していきます。

# データ取得
ユーザ一覧を取得すると仮定しましょう。
まずはコントローラーの`app/controllers/users_controller.rb`にusersテーブルからデータを取得するためのコードを追加します。

```rb:app/controllers/users_controller.rb
def index
  @pagy, @users = pagy(User.all, limit: 4)
    
  respond_to do |format|
    format.html
    format.turbo_stream if turbo_frame_request?
  end
end
```
limitでは一度に表示するデータの数を決めることができます。
バージョンが9.0.0より古い場合、limitではなくitemsでの指定となるので注意してください。

# 表示部分の作成
`app/views/users`内の以下のファイルにコードを追加していきます。
ファイルがない場合はファイルを作成してください。

- index.html.haml
- _user.html.haml
- _pager.html.haml
- index.html+turbo_frame.haml

### index.html.haml
`app/views/users/index.html.haml`に以下を追加します。
```haml:index.html.haml
%h1 ユーザー一覧
%table
  %thead
    %tr
      %th 名前
      %th 住所
      %th 会社名
  = turbo_frame_tag 'page_handler'
  %tbody{id: 'users'}
    = render @users
.more-container
  = render 'pager', pagy: @pagy
```
index.html.hamlには基本的な表示のコードを書きます。
表の中身とボタンは[パーシャル](https://railsguides.jp/layouts_and_rendering.html#%E3%83%91%E3%83%BC%E3%82%B7%E3%83%A3%E3%83%AB%E3%82%92%E4%BD%BF%E3%81%86)を読み込むような形で記述します。

### _user.html.haml
表に表示したい中身を書きます。
`app/views/users/_user.html.hamlに以下を追加します。
```haml:_user.html.haml
%tr
  %td= user.name
  %td= user.address
  %td= user.company
```
`.`以降はuserテーブルから取得したいカラムを指定しています。

### _pager.html.haml
ボタンのコードを書きます。
`app/views/users/_pager.html.hamlに以下を追加します。
```haml:_pager.html.haml
#pager
  - if pagy.next
    = link_to 'more', customers_path(page: pagy.next), data: { turbo_frame: 'page_handler' }
```

### index.html+turbo_frame.haml
ボタンを押した際にパーシャルの置き換え、追加を行うコードを書きます。
`app/views/users/index.html+turbo_frame.haml`に以下を追加します。
```haml:index.html+turbo_frame.haml
= turbo_frame_tag 'page_handler' do
  = turbo_stream_action_tag 'append', target: 'users', template: render(@users).to_s
  = turbo_stream_action_tag 'replace', target: 'pager', template: render('pager', pagy: @pagy).to_s
```
turbo_stream_action_tagについては[こちらのサイト](https://zenn.dev/redheadchloe/articles/d567e7795f0acf)が簡潔でわかりやすいのでおすすめです。
今回は要素の後ろに新しい要素を追加する`append`と要素を置き換える`replace`を使用しています。
これによってボタンを押すたびに表の中身が追加され、次の情報を追加するためのボタンに置き換わります。

# 終わりに
pagyは使い方がわかると簡単にページネーションが作成できる優れものです。
この記事を読んで少しでも参考になると幸いです。
ここまで読んでくださりありがとうございます。

## 参考・引用
https://qiita.com/Bjp8kHYYPFq8MrI/items/514a62aeae5af5821d86