【Rails7】WordPress風メディアライブラリに遅延読み込み(無限スクロール)を実装してみた

つい最近、Railsで自作したブログを公開しましたが、運用するにあたり気になっていたことがありました。

それは、投稿(編集)時におけるメディアライブラリの読み込みに関するものです。

自作ブログでは画像投稿(サムネイル画像の設定含む)もできるよう、新規作成(編集)ページ内にWordPress風のメディアライブラリを作ってみたのですが、

アップロード済みの画像が増えれば増えるほど、新規作成(編集)ページを開くときのページ読み込み時間(正確にはメディアライブラリの全画像の読み込み時間)がえげつないことになってしまいます。

(僕の自作ブログでは画像を大量に使うので、画像をアップロードしまくったおかげで初回読み込み時間が遅くなっていることに気づいたw)

そこで、遅延読み込み(無限スクロール)を実装することで、新規作成(編集)ページを開いたときの初回読み込み時間を改善しようと思った次第です。

当記事では、Rails7で自作したブログに遅延読み込みを実装する流れをご紹介します。

目次

開発環境

  • Ruby 3.1.2
  • Ruby on Rails 7.0.4.3
  • Bootstrap 5.2.3
  • M1 Macbook Air 2020
  • mac OS Monterey (ver. 12.4)

出来上がりイメージ

以下のように、メディアライブラリを開いて下にスクロールするたびに遅延読み込みさせるようにします。

表示する画像サイズにもよりますが、僕の場合は30枚ずつ読み込むよう設定しました。

それでは、具体的な実装方法についてみていきましょう。

遅延読み込み(無限スクロール)を実装する方法

今回ご紹介する遅延読み込み(無限スクロール)は、 Rails7 の Turbo Frames による Lazy Loading とページネーション用Gemである「kaminari」を用いて実装しています。

以上を含めて、下記の前提条件のもと話を進めていきます。

  • Rails7 でアプリ作成
  • kaminari を導入する
  • 記事投稿機能の作成済み(Postモデル)
  • 画像ライブラリ作成済み(active_storage)

画像ライブラリの作成方法については、またいずれ記事にする予定です(気が向いたらw)。

それでは参ります。

ページネーション(kaminari)を導入する

Gemfileに「kaminari」を追記します。

gem "kaminari"

$ bundle installしてGemをインストールします。

コントローラーの編集

アップロード済みの画像をインスタンス変数@imagesとして定義します。

@images = current_user.images.page(params[:page]).per(30).order(created_at: :desc)

ここで、page(params[:page])はkaminariのメソッドで、per(30)とすることで@imagesを30枚ずつ分割して表示するようにします。

(50枚ずつ遅延読み込みしたい場合はper(50)とすればOK)

定義したインスタンス変数@imagesneweditで用いるので、posts_controller.rbに以下のように記述します。

class PostsController < ApplicationController
  before_action :set_images, only: %i[ new edit ]

  def new
  end

  def edit
  end

 ・・・(省略)・・・

  private

  def set_images
    if current_user.images.exists?
      @images = current_user.images.page(params[:page]).per(30).order(created_at: :desc)
    end
  end

 ・・・(省略)・・・

end

turbo_frame_tagを用いて無限スクロールを実装する

最後に、新規・編集用の共通フォームビュー_form.html.erb内の、メディアライブラリを表示させたい箇所に以下のように記述します。

/** アップロード済みの画像をプレビュー(無限スクロール) **/
<% if current_user.images.exists? %>
  <%= turbo_frame_tag "images-page-#{@images.current_page}" do %>
    <% @images.each do |image| %>
      <div class="image-box d-inline-flex justify-content-center mx-1 mb-3" data-action="click->images#selectedImageBox">
        <%= image_tag(image, class: "mx-auto", id: image.blob_id) %>
      </div>
    <% end %>
    <%= turbo_frame_tag "images-page-#{@images.next_page}", loading: :lazy, src: path_to_next_page(@images) %>
  <% end %>
<% end %>

遅延読み込みを行うためにはturbo_frame_tagsrcオプションを使います。

また、以下の3つはkaminariのメソッドになります。

@images.current_page # 今のページ数を返す(例: `0`)
@imagess.next_page # 次のページ数を返す(例: `1`)
path_to_next_page(@images) # 次のページのpathを返す(例: `/images1/`)

具体的な処理の流れを説明すると、

まず以下の<turbo-frame "images-page-2">まで画面をスクロールすると、遅延読み込みにより/images?page=2へTurbo Frameリクエストが実行されます。

// <%= turbo_frame_tag "imagess-page-#{@images.next_page}", loading: :lazy, src: path_to_next_page(@images) 部分 %>
<%= turbo_frame_tag "images-page-2", loading: :lazy, src: "/images?page=2" %>

すると以下の<turbo-frame>を含むHTMLがレスポンスされて、↑の<turbo-frame "images-page-2">を置換します。

/** アップロード済みの画像をプレビュー(無限スクロール) **/
<%= turbo_frame_tag "images-page-2" do %>
  <% @images.each do |image| %>
    <div class="image-box d-inline-flex justify-content-center mx-1 mb-3" data-action="click->images#selectedImageBox">
      <%= image_tag(image, class: "mx-auto", id: image.blob_id) %>
    </div>
  <% end %>
  <%= turbo_frame_tag "images-page-3", loading: :lazy, src: "/images?page=3" %>
<% end %>

そして次は<turbo-frame "images-page-3">のところまでスクロールすると、/images?page=3へTurbo Frameリクエストされ、、

といった具合に、これが最終ページに行くまで無限に繰り返されます。

これで遅延読み込み(無限スクロール)の実装は完了です。

参考資料

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

愛知の34歳。無職で暇になり始めたプログラミング(Ruby on Rails)の忘備録をまとめたブログです。最近は別にやりたいことができたのでプログラミングほぼやっていません。気が向いたらまた再開するかも。僕の日常はメインブログの方で更新しています。

コメント

コメントする

目次