Help us understand the problem. What is going on with this article?

[Rails] 新興のgem pagyをつかってページネーション機能を実装する

More than 1 year has passed since last update.

概要

  • ページネーションといえば、メジャーなのはkaminari, will_pagenateです。しかし、今回は新しく現れたページネーションのgem pagyを使いました。
  • pagyによるページネーションを個人サービスdokodeに導入した時の手順を紹介します。

image.png

環境

  • rails 5.2.1
  • ruby 2.5.1

コード

pagy ?

チョット宣伝。
今回、ページネーションを導入したdokodeは、個人で作っている理系の学会を探すためのサイトです。(まだ、生物系が主ですが、年内に全領域を網羅する予定。)

検索サイトといいつつ、今までは、上位10件のみの表示しかできませんでしたので、ようやくページネーションを導入することにしました。どんな感じの表示になるかはこちら をご覧下さい。

ページネーションというと、kaminariwill_pagenateが有名です。今回もどちらかを使う前提でpagenationの記事を調べていました。せっかくなので、ページネーションの最新情報ないかな?と思って記事を検索したところ Rails:「Pagy」gemでRailsアプリを高速ページネーション(翻訳)のがヒットしました。

今回自分が必要としていたページネーションに求める機能は以下の3つですが、gemのdocumentを読むと、pagyは必要十分な機能があることがわかりました。。

  1. pagenationができる(あたりまえか)
  2. 1ページ辺りの記事数を設定できる
  3. Bootstrap系のview helperがある

また、上記記事とコード的にもpagyのシンプルさも気に入りました。(とくに好きなのは、modelにmethodを生やされないところです。)
これら2つの理由から今回はメジャーな2つのgemをではなく pagyを導入することにしました。

使い方

Quick Startの通りです:relaxed:

インストール

普通にインストールします。

  • Gemfileに記述を追加
gem 'pagy'
  • bundle installを実行
bundle install

コントローラーの設定

pagyを使ってpagenationを実現したいコントローラーに include Pagy::Backend を追加します。今回は HomeControllerで使いたかったので以下のように記述を追加します。

class HomeController < ApplicationController
  include Pagy::Backend

使いたいアクションのところでモデルを引数にして結果を受け取ります。今回は、 @event_search.exec.includes(:venues)Event.where(nam: hogehoge).includes(:venues) みたいなかんじの結果を返すので、以下のように書きます。

app/controllers/home_controller.rb
  def search
    @event_search = if params[:event_search].present?
                      EventSearch.new(event_search_params)
                    else
                      EventSearch.new
                    end
    @pagy, @events = pagy(@event_search.exec.includes(:venues))
  end

まぁ、普通の状況だと @pagy, @events = pagy(Event.where(name: 'kensak keyword') でしょう。

1ページ辺りの数を10個にする

config/initializers配下にpagy.rbを配置し、以下の記述を追加します。(追加したら railsの再起動必要です。)
なお、 公式で用意しているこちらのpagy.rbを使って、コメントを外して使っても可です。

config/initializers/pagy.rb
# Instance variables
# See https://ddnexus.github.io/pagy/api/pagy#instance-variables
Pagy::VARS[:items] = 10

Viewファイルの設定

@events を使うだけ。なお、もし、draperを使っているなら、 .decorateをつけてあげればOK。

app/views/home/search.html.erb
        <div class="row">
          <%= render partial: 'home/event_card', collection: @events.decorate, as: :event, locals: {event_search: @event_search, keyword_array: @event_search.keyword_array, omit_content: false} %>
        </div>

また、検索結果総数を受け取るためには @pagy.vars[:count] でとれます。kaminariでいえば '@events.total_count' の機能です。
以下のような感じでつかって0件の検索結果との場合分けに使えます。

      <% if @pagy.vars[:count] > 0 %>
        検索結果がある場合の表示
      <% else %>
        <div class="d-flex justify-content-center">
          <div class="display-4">
            <p>
              <%= @event_search.keyword %> の 検索結果は 0 件です。
            </p>
            <p>
              キーワードを見直してください。
            </p>
          </div>
        </div>
      <% end %>

なお参考までに、 @pagy.varsp @pagy.vars で出力すると以下の通りのデータが各伸されていました。

{:page => 1, :items => 10, :outset => 0,
 :size => [1, 4, 4, 1], :page_param => :page,
 :params => {},
 :anchor => "",
 :link_extra => "",
 :item_path => "pagy.info.item_name",
 :breakpoints => {0 => [1, 4, 4, 1]},
 :count => 19}

Bootstrapに対応したナビゲーションヘルパーの追加

最後に、ページのナビゲーションようのパーツを追加します。
pagyは以下のcssフレームワークに対応したナビゲーションヘルパーを用意しています。

今回は、bootstrapのデザインを適用したパーツを使います。

bootstrapのパーツを使うためには、pagy.rbで Extras を有効にします。
と、いっても、既に上述の工程で pagy.rbは追加されていると思いますので、pagy.rbに下記の記述を追加するだけです。(追加したら railsの再起動必要です。)

config/initializers/pagy.rb
# Bootstrap: Nav, responsive and compact helpers and templates for Bootstrap pagination
# See https://ddnexus.github.io/pagy/extras/bootstrap
require 'pagy/extras/bootstrap'

ナビゲーションヘルパー <%== pagy_nav_compact_bootstrap(@pagy) %> viewファイルに追加します。

app/views/home/search.html.erb
      <% if @pagy.vars[:count] > 0 %>
        <div class="d-flex justify-content-center mb-2">
          <%== pagy_nav_compact_bootstrap(@pagy) %>
        </div>

追加すると以下のような表示になります。

image.png

ちなみに <%== pagy_nav_bootstrap(@pagy) %> にすると以下の感じです。
こちらの方が見慣れている人おおいですかね。

image.png

これでページネーション完成です。」

オマケ

pagyはkaminariよりも速い!と紹介されていたので、期待して簡易ベンチマーク撮りました。・・・が差は見られませんでした。

kaminariとpagyの読み込み時間を5回計測して比較したのですが、、、あまり差がありませんでした。1000件ぐらいだとこんなもんなんですかね。

対象ページ http://localhost:3000/search?utf8=%E2%9C%93&event_search%5Bkeyword%5D=&button=
対象件数 1327件

kaminariで実装
web_1  | Completed 200 OK in 437ms (Views: 382.3ms | ActiveRecord: 33.5ms)
web_1  | Completed 200 OK in 535ms (Views: 494.3ms | ActiveRecord: 14.7ms)
web_1  | Completed 200 OK in 605ms (Views: 554.8ms | ActiveRecord: 18.7ms)
web_1  | Completed 200 OK in 648ms (Views: 591.9ms | ActiveRecord: 16.9ms)
web_1  | Completed 200 OK in 601ms (Views: 555.5ms | ActiveRecord: 15.6ms)

pagyで実装
web_1  | Completed 200 OK in 589ms (Views: 536.8ms | ActiveRecord: 22.2ms)
web_1  | Completed 200 OK in 603ms (Views: 556.5ms | ActiveRecord: 16.2ms)
web_1  | Completed 200 OK in 458ms (Views: 406.9ms | ActiveRecord: 23.2ms)
web_1  | Completed 200 OK in 391ms (Views: 348.7ms | ActiveRecord: 15.6ms)
web_1  | Completed 200 OK in 447ms (Views: 400.0ms | ActiveRecord: 17.5ms)

差があったらばばーんとグラフ作ろうと思ったのに残念。

junara
10年間医療の研究していたが、Webサービス作りたくて、エンジニアへ。 Rails, Javascritptのエンジニアとして働きながら、生命科学学会検索サービスを作りました。 https://www.dokode.work
bldt
"Your growth, Improve the world" をビジョンに掲げ、自社事業やシステム開発サービスを提供しています
https://bldt.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away