LoginSignup
3
3

More than 5 years have passed since last update.

Ruby Gem Pagy + Infinite-Scroll PluginでAPIレスポンスデータを無限スクロールする

Last updated at Posted at 2019-04-01

最近、Ruby on Railsで、APIの結果を無限スクロールで表示する画面を作成する機会があり、ページネーション用のGemを探していたところ「Pagy」を知りました。ページネーションのGemで有名なものは、「Kaminari」や「Will Pagenate」ですが、これらのGemに比べて「Pagy」はパフォーマンス面に重点をおいて開発されているとのことで、興味を持ち使ってみました。

目的

Pagyの公式ドキュメントはとても充実していますが、日本語の情報がまだ少なかったので、今回は「Pagy」の使用方法について記載していこうと思います。なお、パフォーマスについては、ベンチマークテストの結果がGithub上に掲載されていますので、興味のある方はそちらをご覧下さい。

やること

  1. Pagyを用いたページネーション
  2. Infinite-Scroll Pluginを用いた無限スクロール

データ

今回は、Modelから取得したデータではなく、APIレスポンスのデータをページネーションさせます。APIから受け取ったJSONデータをHashに変換後、配列形式でPagyへ渡すイメージです。なお、今回はPagyの利用が目的ですので、実際にAPIを用意することはせず、Controller内に配列データを直接定義します。

環境

本記事では、以下の環境を使用します。

  • Ruby 2.4.1
  • Rails 5.1.6
  • Pagy 2.1.3
  • Slim 4.0.1

Pagyのインストール

まずは、Gemfileに「pagy」を追加します。

Gemfile
gem 'pagy'

Gemを追加したら、インストールします。

bash
bundle install --path vendor/bundle

Controllerの設定

ControllerにPagyのBackendモジュールをインクルードします。

app/controllers/contents_controller.rb
class ContentsController < ApplicationController
  include Pagy::Backend
end

Helperの設定

HelperにPagyのFrontendモジュールをインクルードします。

app/helpers/contents_helper.rb
module ContentsHelper
  include Pagy::Frontend
end

Pagyのイニシャライザファイル作成

イニシャライザファイルを作成することで、Pagyの設定をデフォルトから変更することができます。例えば、1ページに表示するデータ件数を指定したり、国際化対応の設定ができたりします。
今回は、配列に対してページネーションを行うために必要なライブラリの読み込みだけを行います。
その他の設定可能な項目については知りたい方は、Pagyのgithub上に公開されているので、そちらをご覧下さい。

config/initializers/pagy.rb
require 'pagy/extras/array'

ページング処理の実装

配列をページング処理するには、pagy_arrayというメソッドに、ページング処理したい配列を渡し、その返り値をViewで使用します。なお、オプション引数としてハッシュを渡すことで、様々な指定をすることができます。下記サンプルの「items: 3」は1ページあたりの表示データ数を3つにすることを意味しています。オプション引数で指定できる内容は、Pagyのイニシャライザファイルで定義することも可能です。
上記でも説明したように、ページネーションさせるデータはdefine_dataメソッドとして、直接定義してます。

app/controllers/contents_controller.rb
class ContentsController < ApplicationController
  include Pagy::Backend

  def search
    @api_results = define_data
    @pagy, @api_results = pagy_array(@api_results, items: 3)
  end

  def define_data
    results = [
      { id:  1, content: 'test data 01', date: '2019/04/01 10:01:00' },
      { id:  2, content: 'test data 02', date: '2019/04/01 10:02:00' },
      { id:  3, content: 'test data 03', date: '2019/04/01 10:03:00' },
      { id:  4, content: 'test data 04', date: '2019/04/01 10:04:00' },
      { id:  5, content: 'test data 05', date: '2019/04/01 10:05:00' },
      { id:  6, content: 'test data 06', date: '2019/04/01 10:06:00' },
      { id:  7, content: 'test data 07', date: '2019/04/01 10:07:00' },
      { id:  8, content: 'test data 08', date: '2019/04/01 10:08:00' },
      { id:  9, content: 'test data 09', date: '2019/04/01 10:09:00' },
      { id: 10, content: 'test data 10', date: '2019/04/01 10:10:00' },
      { id: 11, content: 'test data 11', date: '2019/04/01 10:11:00' },
      { id: 12, content: 'test data 12', date: '2019/04/01 10:12:00' },
      { id: 13, content: 'test data 13', date: '2019/04/01 10:13:00' },
      { id: 14, content: 'test data 14', date: '2019/04/01 10:14:00' },
      { id: 15, content: 'test data 15', date: '2019/04/01 10:15:00' },
      { id: 16, content: 'test data 16', date: '2019/04/01 10:16:00' },
      { id: 17, content: 'test data 17', date: '2019/04/01 10:17:00' },
      { id: 18, content: 'test data 18', date: '2019/04/01 10:18:00' },
      { id: 19, content: 'test data 19', date: '2019/04/01 10:19:00' },
      { id: 20, content: 'test data 20', date: '2019/04/01 10:20:00' },
      { id: 21, content: 'test data 21', date: '2019/04/01 10:21:00' },
      { id: 22, content: 'test data 22', date: '2019/04/01 10:22:00' },
      { id: 23, content: 'test data 23', date: '2019/04/01 10:23:00' },
      { id: 24, content: 'test data 24', date: '2019/04/01 10:24:00' },
      { id: 25, content: 'test data 25', date: '2019/04/01 10:25:00' },
      { id: 26, content: 'test data 26', date: '2019/04/01 10:26:00' },
      { id: 27, content: 'test data 27', date: '2019/04/01 10:27:00' },
      { id: 28, content: 'test data 28', date: '2019/04/01 10:28:00' },
      { id: 29, content: 'test data 29', date: '2019/04/01 10:29:00' },
      { id: 30, content: 'test data 30', date: '2019/04/01 10:30:00' }
    ]
  end
end

これでページングさせるデータの準備はできたので、次にビュー側の処理を書いていきます。なお、divタグの「contents」というIDと、「content」というclass名は任意ですが、無限スクロール実装時にJavaScript側で使用するので、変更する場合はご注意下さい。

app/views/contents/search.html.slim
#contents
  .content
    - @api_results.map do |result|
      div
        = "内容:#{result[:content]}  |  作成日時:#{result[:date]} "
== pagy_nav @pagy

ページネーション 動作確認

ここまで実装すると、下記のようにページングが行えるようになっているはずです。
「2」や「3」、「Prev」、「Next」が機能することを確認しましょう。
step1.png

無限スクロールの導入

作成したページングを無限スクロールへ変更していきます。
まずは、下記よりJavaScriptのプラグインを取得し、「app/assets/javascripts/」直下に配置します。

次に、無限スクロールを行うViewに対応するJavaScriptを作成します。

app/assets/javascripts/contents.js
$(document).on('turbolinks:load', function () {
  $('#contents').infiniteScroll({
    path: "nav.pagination a[rel=next]",
    append: ".content",
    hideNav: '.pagination',
    history: false,
    prefill: true,
    status: '.page-load-status'
  })
});

指定しているオプションの意味は、下記の通りです。

  • path: "nav.pagination a[rel=next]"・・・次のページへのリンクを指定
  • append: ".content"・・・追加する要素を指定
  • hideNav: '.pagination'・・・ページングのナビゲーションを非表示
  • history: false・・・ページの変更ごとにブラウザの履歴とURLを変更しない
  • prefill: true・・・初期化時にロードして、要素を追加
  • status: '.page-load-status'・・・ページ読み込みの状態を示すステータス要素を表示

最後に、JQueryを読み込むように設定します。

app/assets/javascripts/application.js
//= require jquery

無限スクロール 動作確認

再度、画面を確認すると、無限スクロールが実現できているはずです。
うまく動かない場合は、Slimのインデント、divタグのIDやclass名を確認してみて下さい。
step2.png

ソースコード

実際に手元でコードを動かしたい方は、下記よりcloneしてご使用下さい。

参考

3
3
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
3
3