2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

最新のRuby on Railsに一人で迫ってみる挑戦Advent Calendar 2023

Day 12

Turboを使った無限スクロールが簡単すぎて感動した

Posted at

はじめに

本記事は錆びかけたRailsの知識を頑張ってアップデートするアドベントカレンダー12日目です。

Turboを使うと、無限スクロールの実装が驚くほど簡単にできます。

無限スクロールとは

ある程度スクロールすると続きのコンテンツがロードされるようなUIです。

一番馴染み深いのはTwitter(X)のアプリの挙動です。タイムラインをスクロールしていくと、自動で続きが読み込まれますね。

Turboを利用した無限スクロールの実装を見た時、あまりの簡単さに感動したので、やり方をチュートリアル形式でごく簡単に紹介します。

対象読者

Ruby on Railsを学習中の人
Railsですでに簡単なアプリケーションを作成したことがある人
※まだRailsについてよくわかっていないよ、という方は対象ではありません。

事前準備

以下の環境で実装を行います。必要に応じて環境構築してください。

  • Ruby 3.2.0
  • Rails 7.0.5
  • MySQL 8系
  • OS: MacOS Monterey バージョン 12.6.2

以下の記事はDockerで上記の環境を作る記事となっています。
Docker for MacをインストールしてRails7 + MySQL8の環境を作る

ここでは、Rails7系でrails newして、アプリの雛形ができていると想定します。Rubyの該当バージョンやRails7系がインストールできていれば

ローカルサーバの立ち上げ方に注意

Railsはこれまでrails sコマンドを使ってローカルサーバを立ち上げていました。Rails7からは、bin/devというコマンドで立ち上げるようになっています。

bin/devというコマンドについては以下の記事を参照してください。
bin/devって何だ

bin/devコマンドを使ってローカルサーバを立ち上げ、Google Chromeなどのブラウザからlocalhost:3000にアクセスして以下のように表示されていれば準備OKです。

fejwaau.png

Turboによる無限スクロール体験ハンズオン

作るもの

202312141.gif

手順

tweetモデルとテーブルを作成する
tweetsテーブルにダミーデータを100件投入する
一覧ページでtweet一覧を100件表示する
ページネーションを実装する
無限スクロールを実装する

tweetモデルとテーブルを作成する

まずは、無限スクロールを試すリソースを用意します。今回はtweetというモデルとし、表示する中身はcontentという属性値にします。以下のコマンドで、モデルとマイグレーションファイルを作成します。

tweetモデルの作成
docker compose run i-scroll-web rails g model tweet content:string

続いてマイグレーションファイルを読み込みテーブルを作成します。

tweetモデルの作成
docker-compose run i-scroll-web rails db:migrate

tweetsテーブルにダミーデータを100件投入する

tweetsテーブルを作成できたので、ダミーデータを投入します。

今回はgem fakerを使います。

Gemfile
// Gemfileの一番下に追記
gem "faker"

bundle installします。

ターミナル
docker-compose run i-scroll-web bundle

seeds.rbの中身を以下のように書き換えます。

require 'faker'

100.times do |i|
  Tweet.create(content: Faker::Lorem.sentence(word_count: 5), nickname: Faker::Internet.username)
end

作成したseeds.rbを実行します。これで、tweetsテーブルにレコードが100件保存されます。

ターミナル
docker-compose run i-scroll-web rails db:seed

一覧ページでtweet一覧を100件表示する

続いて一覧ページを作成します。コントローラやviewはscaffoldで作成します。

ターミナル
rails g scaffold_controller Tweet

これで、必要なルーティング/コントローラ/ビューの準備が整います。以下のようなファイルが作成されていればOKです。
手動で作成しても構いません。

routes.rb
Rails.application.routes.draw do
  resources :tweets
end
tweets_controller.rb
class TweetsController < ApplicationController
  before_action :set_tweet, only: %i[ show edit update destroy ]

  # GET /tweets
  def index
    @tweets = Tweet.all
  end

 # 以下略
end

views/tweets/index.html.erb
<p style="color: green"><%= notice %></p>

<h1>Tweets</h1>

<div id="tweets">
  <% @tweets.each do |tweet| %>
    <%= render tweet %>
    <p>
      <%= link_to "Show this tweet", tweet %>
    </p>
  <% end %>
</div>

<%= link_to "New tweet", new_tweet_path %>

_tweet.html.erb

  <div id="<%= dom_id tweet %>" style="padding:20px 0">
    <%= tweet.content %>
  </div>

ページネーションを実装する

続いてページネーションを実装します。ページネーションとは、表示すべきコンテンツが多すぎる際に一定の数で区切り、続きを見る際は「2,3,4・・・」のようなリンクを押す形のUIです。

ページネーションはgem kaminariで実装します。Gemfileに以下のように追記します。

Gemfile
# 下部に追記
gem "faker"
gem 'kaminari'

bundle installします。

ターミナル
docker-compose run i-scroll-web bundle

tweets_controller.rbのindexアクションの中身を、kaminariの仕様にそった形に書き換えます。

tweets_controller.rb
class TweetsController < ApplicationController
  before_action :set_tweet, only: %i[ show edit update destroy ]

  # GET /tweets
  def index
    @tweets = Tweet.order(created_at: :desc).page(params[:page]).per(40)
  end

 # 以下略
end

これで、一覧ページの最初の表示時には40件しかツイートが表示されないことになります。

無限スクロールを実装する

ここが肝です。

無限スクロールには、Turbo Frameを利用します。

views/tweets/index.html.erb
<div class="tweet-page" style="padding:10px 40px">
  Tweets
  <%# 今のページの`<turbo-frame>` %>
  <%= turbo_frame_tag "tweets-page-#{@tweets.current_page}" do %>
    <%# 今のページで取得したTweet一覧 %>
    <%= render @tweets %>

    <%# 遅延読み込みで次ページを取得する`<turbo-frame>` %>
    <%= turbo_frame_tag "tweets-page-#{@tweets.next_page}", loading: :lazy, src: path_to_next_page(@tweets) %>
  <% end %>
</div>

これだけです。

たったのこれだけで、tweet一覧画面が無限スクロールになります。

書く量が少なすぎる。。。

なぜ無限スクロールになるのか

書き換えたindex.html.erbのポイントは以下の通りです。

turbo_frame_tag ~ do<render @tweets>を囲った
turbo_frame_tagloading: :lazyオプションで遅延読み込みを行った

turbo_frame_tag ~ do ~ end<render @tweets>を囲った

turbo_frame_tag ~ do ~ endで囲った部分は、リクエストがTurboのリクエストとなります。

Turboのリクエストは非同期になり、ページを切り替えません。

その時リクエストするのが、次節で説明するloading: :lazyがついたturbo_frame_tagの読み込みです。

turbo_frame_tagloading: :lazyオプションで遅延読み込みを行った

turbo_frame_tagでこのオプションがついている場合、の要素が読み込まれたタイミングでsrcへのリクエストをします。
今回、kaminariを使ったpaginationのオプションを利用して次のページの番号を取ったり、次のページを取るためのリクエストURLを準備しています。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?