Rails+Turboで無限スクロールをさくっと作る
以下記事にてTurboを使用した無限スクロールの例が面白かったので実際に作りながら確認してみました。
事前準備
RubyやRailsに関しては以下バージョンです
Ruby: 3.3.0
Rails: 7.1.3
tailwindcss入れておくとscaffoldの画面が綺麗に見えるのでそれは入れてその他はデフォルトのままにします。
$ rails new infinite_scroll -c tailwind
$ cd infinite_scroll
$ bin/rails tailwindcss:install
scaffoldとseedsを使って適当なデータを作成します。
$ bin/rails g scaffold Post content:text
$ bin/rails db:migrate
あとはseedsデータを準備します。ダミーテキストは夏目漱石のこころから。
長さ変わったほうがわかりやすいかなということで適当にsliceしてます。
text = "伯父も首を傾けました。しかも私の受けたその時の私がもしこの驚きをもって、その墓を見た時は、もう帰りませんでした。私はそれを緒口にまた話を始めました。あなたのお父さんが亡くなられるのを、ちょうど嫁でも貰った。彼の眼の前に立っていましたから、普通の人間として、私はそんな上の空でいってる事じゃないんだと私は見込んでいたのです。そうして八畳の中をあちらこちらと泳いでいるのだろうか。幸いにKの黒い姿はそこに私の返事を出そうかと考えて、かえって変な反撥力を感じた。先生が奥さんと話していた。潔癖な父は、単なる娯楽の相手というのです。必竟やくざだから遊んでいるので、ほとんど新聞を読む暇がなかった。"
100.times do |i|
Post.create!(content: text.slice(0, rand(1..100)))
end
seedsの変更が終わったのでDBに入れます。
$ bin/rails db:seed
次にページネーションを実装するgemを入れます。元記事ではpagyを入れていますが今回は個人的な好みでkaminariを入れます。
$ bundle add kaminari
無限スクロールを作る
controllerから触っていきます。さきほどkaminariを入れたのでkaminariに適応させましょう。
def index
- @posts = Post.all
+ @posts = Post.all.page(params[:page]).per(10)
end
controllerができたので次はviewを触ります。
render @posts
になっている部分を修正していきます。
- <%= render @posts %>
+ <%= turbo_frame_tag "posts_page_#{@posts.current_page}" do %>
+ <%= render @posts %>
+
+ <% if @posts.next_page %>
+ <%= turbo_frame_tag "posts_page_#{@posts.next_page}",
+ src: posts_path(page: @posts.next_page),
+ loading: :lazy
+ %>
+ <% end %>
+ <% end %>
これでできました!早い!サーバーを立ち上げて見てみましょう。
下にスクロールすればどんどん読み込みが進んで無限スクロールが実装できているかと思います。
仕組みとしては loading="lazy"
が指定されていることによってスクロールが下のほうに近づいたタイミングで posts_path(page: @posts.next_page)
へアクセスされます。
posts#indexのviewの中には次ページのID(posts_page_2
など)を含んだturbo-frameが含まれているのでその部分が置き換えされて次のページへアクセスできます。
それがデータの終わりまでアクセスされるので無限スクロールが出来る、ということになります。
<turbo-frame>
が入れ子構造になっていくので形として面白いです。
これだけで無限スクロールが出来るのはとても便利なのですが少し問題もあります。
例えば別ページのものを表示してブラウザの「戻る」をクリックするとturbo-frameで読み込まれたものがすべてリセットされてしまう問題があります。
なのでこれを使うのであれば「戻る」を想定していない場所で使うのがいいかなと思います。
Discussion