Railsでページネーションを自作する
Railsでページネーションをgemを使わないで実装した事について書きます。
「ページネーションを使える様にしましょう」という事は良くあり、、というかWEB開発では必ずある。
今まではRailsでは kaminari とか will_paginate を使ってきて、便利だし個人的には使えば良いと思っている。
今回は特殊な事情から自作する事になった。
何故自作したか
- アプリの構成が特殊で、kaminariを使おうとしたけど何故かkaminariが正常にロードされなかった。
1.
の問題を深掘りしたい気持ちもあったものの、作ってしまった方が早いとなった。- カスタマイズしやすいし、アプリの影響範囲もわかるので自作の良い点も多い。
ページネーションの処理をmodelによせたかった
初めはコントローラ側にページネーションの処理を書いていたのですが、
コントローラにこんな感じのコードが複数発生してきて、共通化できる様にしたかった。
@page = params[:page].to_i < 1 ? 1 : params[:page].to_i @offset = PER_PAGE * (@page - 1) relation = Huga.where(coditions) @hugas = relation.offset(@offset).limit(PER_PAGE).order(id: :desc) @total_count = relation.count
modelに移した
modelに移す上で、kaminariのコード を見てみると、ActiveRecord::QueryMethods#extending というメソッドが使われている。
ActiveRecord::Relation
にメソッドを追加したり拡張ができるみたいで便利!
ドキュメントの例もページネーションだし、これ使ってみようという気持ちになる。
という事で実装してみた所、以下の感じになった。簡単・・・。
module Hoge module Concerns module Paginate extend ActiveSupport::Concern included do scope :page, ->(page, per_page) do all.extending(Hoge::Concerns::Paginate::Extends).paginate(page, per_page) end end module Extends def paginate(page, per_page) @current_page = page.to_i < 1 ? 1 : page.to_i offset = per_page * (@current_page - 1) offset(offset).limit(per_page) end def current_page @current_page end def limit_value self.values[:limit] end def offset_value self.values[:offset] end def total_count except(:limit, :offset).count end end end end end
使い方
class Huga < ApplicationRecord include Hoge::Concerns::Paginate end hugas = Huga.page(3, 30) # 1ページ30件の3ページ目を取得する hugas.current_page # 3 hugas.limit_value # 30 hugas.offset_value # 60 hugas.total_count # 全件の件数