Rails Advent Calendar 11 日目です。
Railsの定番paginatorと言えばkaminariです。Railsで開発をしたことがあれば、少なくとも名前くらいは聞いたことがあるでしょう。
大変使いやすく、ほぼゼロコンフィグでページネーションできますが、ドキュメントがシンプルなこともあって、ちょっと凝ったことをしようとすると情報を探すのに苦労します。
と言うわけで「kaminariを使って三日目」くらいの人向けに書いてみます。
Why kaminari?
まずは基本的なところをおさらいします。
ActiveRecordオブジェクトをkaminariでpaginateするには、以下のようなコードを書きます。(Gemfileは設定済みとします)
Item.page
Item.all.pageとしてはいけません。
これは以下のようなSQLを発行します。
puts Item.page.to_sql
#=> SELECT `items`.* FROM `items` LIMIT 25 OFFSET 0
puts Item.page(3).to_sql
#=> SELECT `items`.* FROM `items` LIMIT 25 OFFSET 50
引数に整数を渡すとOFFSETが加算されていきます。
pageメソッドはActiveRecord::Relationオブジェクトを受け取ってActiveRecord::Relationオブジェクトを返すため、whereメソッドなどで絞り込んだ結果に対してpageメソッドを実行したり、pageメソッドで得られた結果に対してさらに操作したりできます。
また、一度に全てのレコードを取得しないので実行速度やメモリの点で有利です。
基本
ページネーションするには以下のようにします。
def index
@items = Item.page(params[:page])
end
<%= paginate @items %>
とりあえずこれだけで目的は達せます。
1ページの件数を変えたい
コントローラで都度変更するなら以下のようにします。
def index
@items = Item.page(params[:page]).per(10)
end
デフォルトを変更するなら、モデルに以下の一行を追加します。
paginates_per 10
デフォルトは25です。
見た目を変えたい
kaminari組み込みのデザインは十分クールだと思いますが、デザインを合わせたいなどということもあるでしょう。その場合は以下のようにします。
まず、以下のコマンドを実行します。
rails g kaminari:views default
これでapp/views/kaminari以下にテンプレートが書き出されるので、それを変更します。
テンプレートの先頭に利用可能なローカル変数の一覧が出ているので、それを参考にクラスなどを設定していけば好みのデザインにできるでしょう。
なお、Twitter Bootstrapを使う場合、kaminariデフォルトのままだとbootstrapのクラスとぶつかって正しく表示されません。
手で直しても良いですが、便利なスニペットがあります。
twitter-bootstrap-kaminari-views
これをcloneして上書きすればbootstrapできちんと表示されます。
hamlバージョンもあります。
よく使うAPI
@item.total_count #=> レコード総数
@item.offset_value #=> オフセット
@item.num_pages #=> 総ページ数
@item.per_page #=> 1ページごとのレコード数
@item.current_page #=> 現在のページ
@item.first_page? #=> 最初のページならtrue
@item.last_page? #=> 最後のページならtrue
例
ページ:<%= @item.current_page %> / <%= @item.num_pages %>
<%= @item.total_count %>件中<%= @item.offset_value %>
〜<%= @item.offset_value + @item.length %>件を表示しています。
Ajax
Ajaxでページネーションするには、ビューを以下のようにします。
<%= paginate @items, :remote => true %>
これだけでxhrでリクエストが行われますが、実際に書き換えを行う部分は自分で用意してやる必要があります。以下は一例です。
def index
@items = Item.page params[:page]
respond_to do |format|
format.html
format.js
end
end
$("#items").html("<%= j(render :partial => 'items') %>");
<div id="items">
<%= render :partial => "items" %>
</div>
<%= paginate @items %>
<% @items.each do |item| %>
以下略
その他
ActiveRecordの例のみを紹介しましたが、kaminariはMongoidやDataMapperにも対応しています。また、Arrayオブジェクトをページネーションすることも可能です。
ドキュメントは整備されているとは言えませんが、ソースは読みやすくまたコーディングの参考にもなるので、興味があったら是非読んでみることをお勧めします。