• 382
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

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メソッドで得られた結果に対してさらに操作したりできます。
また、一度に全てのレコードを取得しないので実行速度やメモリの点で有利です。

基本

ページネーションするには以下のようにします。

items_controller.rb
def index
  @items = Item.page(params[:page])
end
index.html.erb
<%= paginate @items %>

とりあえずこれだけで目的は達せます。

1ページの件数を変えたい

コントローラで都度変更するなら以下のようにします。

items_controller.rb
def index
  @items = Item.page(params[:page]).per(10)
end

デフォルトを変更するなら、モデルに以下の一行を追加します。

item.rb
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

page_info.html.erb
ページ:<%= @item.current_page %> / <%= @item.num_pages %>
<%= @item.total_count %>件中<%= @item.offset_value %>
<%= @item.offset_value + @item.length %>件を表示しています。

Ajax

Ajaxでページネーションするには、ビューを以下のようにします。

index.html.erb
<%= paginate @items, :remote => true %>

これだけでxhrでリクエストが行われますが、実際に書き換えを行う部分は自分で用意してやる必要があります。以下は一例です。

items_controller.rb
def index
  @items = Item.page params[:page]
  respond_to do |format|
    format.html
    format.js
  end
end
index.js.erb
$("#items").html("<%= j(render :partial => 'items') %>");

index.html.erb
<div id="items">
  <%= render :partial => "items" %>
</div>
<%= paginate @items %>
_items.html.erb
<% @items.each do |item| %>
以下略

その他

ActiveRecordの例のみを紹介しましたが、kaminariはMongoidやDataMapperにも対応しています。また、Arrayオブジェクトをページネーションすることも可能です。
ドキュメントは整備されているとは言えませんが、ソースは読みやすくまたコーディングの参考にもなるので、興味があったら是非読んでみることをお勧めします。