🦓

[Rails]turbo_streamとpagyで無限スクロールを実装する 1/2

2023/09/07に公開

はじめに

turbo_streampagyを使って無限スクロールを実装していきます。

https://github.com/ddnexus/pagy
https://ddnexus.github.io/pagy/docs/how-to/

環境

Rails 7.0.7
ruby 3.2.1

流れ

1. Fakerでダミーデータを作成する
2. pagyをインストールする
3. 初期ファイルを作成する
4. 投稿にPagyを導入する
5. ページネーションリンクを追加する
6. turbo_streamを使って新しい投稿内容をページの下にリロードせずに追加されるようにする
6-1. POSTリクエスト用URLを追加する
6-2. もっと見るボタンを作成する
6-3. turbo_streamパーシャルを作成し、取得された投稿をパーシャル内に表示させる

Fakerを使ってダミーデータを作成する

投稿を100件作成します。

app/seeds.rb
100.times do |i|
    title = "タイトル#{i + 1}"
    Post.create(title: title, 
                body: Faker::Quote.famous_last_words, 
                user_id: User.first.id)
end
bin/rails db:seed

Pagyをインストールする

Gemfile
gem 'pagy'
bundle install

Pagyをインクルードする

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include Pagy::Backend
end
app/helpers/application_helper.rb
module ApplicationHelper
  include Pagy::Frontend
end

無限スクロール用初期ファイルを作成する

config/initilizers/ディレクトリ内pagy.rbを作成し、無限スクロール用モジュールを導入します。

config/initilizers/pagy.rb
require 'pagy/extras/countless'

ドキュメントを参考して進めていきます。
https://ddnexus.github.io/pagy/docs/extras/support/

サーバーを再起動します。

投稿にPagyを導入する

投稿をページごとに10件ずつ表示するようにします。

app/controllers/posts_controller.rb
class TodosController < ApplicationController
...
  def index
    @pagy, @posts = pagy_countless(Post.includes(:user).order(created_at: :desc), items: 10)
  end
end

ビューにページネーションリンクを追加する

app/views/posts/index.html.erb
<%== pagy_next_link(@pagy, text: 'More...', link_extra: 'id="next_link"') %>

ここでページネーションを実装されたことを確認します。URLがposts?page=1posts?page=2...になっています。

現状ページをリロードして新しい投稿を取得していますが、turbo_streamを使って非同期に投稿コンテンツを取得しページを動的に更新していきます。

POSTリクエスト用URLを追加する

config/routs.rb
resources :posts do
  collection do
    post :index
  end
end

コントローラーにturboリスポンスに対応するコードも追加します。

app/controllers/posts_controller.rb
class TodosController < ApplicationController
  def index
...
    respond_to do |format|
       format.turbo_stream
       format.html
    end
  end
end

もっと見るボタンを作成する

デフォルトのリンクを書き換えて投稿の下に追加します。

app/views/posts/index.html.erb
<%= link_to 'もっと見る', pagy_url_for(@pagy, @pagy.next) %>

pagy_url_for

pagy_url_forはPagyのヘルパーメソッドで、ページネーションリンクのURLを生成するために使用されます。通常、ページネーションのリンクをカスタマイズする必要がある場合に使います。

pagy_url_for(pagy, page)
  • pagy: Pagyオブジェクトです。通常、コントローラーアクション内でpagyメソッドを使用して生成されたものを渡します。
  • page: リンクを生成するページ番号を指定します。これは通常、ページネーションリンクを生成するためのリンク先ページの番号です。

index.turbo_stream.erbパーシャルを作成する

app/views/posts/index.turbo_stream.erb
<%= turbo_stream.append "posts" do %>
  <%= render @posts %>
<% end %>

<%= turbo_stream.replace "load_more_btn" do %>
  <%= link_to 'もっと見る', pagy_url_for(@pagy, @pagy.next), data: { turbo_method: :post } %>
<% end  %>

_load_more_btn.html.erbパーシャルを作成した方が良いですが、テストのために投稿の下に直接書いてます。

Image from Gyazo

問題なさそうですが、投稿ない場合もっと見るボタンーを非表示にさせたいのでif文を追加します。

app/views/posts/index.turbo_stream.erb
<%= turbo_stream.replace "load_more_btn" do %>
  <%= link_to 'もっと見る', pagy_url_for(@pagy, @pagy.next), 
  data: { turbo_method: :post }
+ if @pagy.next.present?  %>
<% end  %>

Image from Gyazo

終わりに

turbo_streampagyによる無限スクロールでした。
ボタン無しのパターンもまとめましたので良かったら参考にしてみてください。

参考した記事:
https://www.bearer.com/blog/infinite-scrolling-pagination-hotwire

Discussion