Rails 2.2.2でページネーション

既出だが、Rails1.xでは標準だったページネーション機能が2.0以降は省かれているため、Railsのプラグインとして別途導入する必要がある。

Home - mislav-will_paginate - GitHub

Rails 1.2相当のpaginateはclassic_paginateだが、今更古いバージョンを使うこともないので、最初からこれを使う。

  • 導入

Downloads for mislav's will_paginate - GitHubから、最新版(今回はv2.3.7)をダウンロード

巷ではwill_paginateはGitHubに移行したのと同時にgem形式での配布に変わったはずなんだが、ダウンロードしたアーカイブはどう見てもgem形式ではない。

Wiki(Installation - will_paginate - GitHub)を見てみると通常は下記のようにGitHubのリポジトリをgemに追加してインストールするらしいのだが、

$ gem sources -a http://gems.github.com
$ sudo gem install mislav-will_paginate

ご存じの通り私の仕事環境はDMZにありNTLM認証でプロキシを使わないと外に出れないため、gemのリモートからのインストールは現時点では不可能。
幸いにも上記でダウンロードしたアーカイブはプラグインの展開イメージのようなので、今回はtarballsを直接$RAILS_HOME\vendor\pluginsに展開して使うことにした。(この際、ディレクトリ名を"will_paginate"に修正する必要がある)

なお、この方法だとRailsプロジェクト毎にwill_paginateをインストールする必要があるので注意

  • 使い方

様々なオプションを指定できるが、超絶簡単な方法としてscaffoldで生成されたアプリケーションに対してページナビゲーション機能を追加することを考えてみる。

1. コントローラの修正
RESTfulなscaffoldであれば、indexアクション(メソッド)中のモデルのファインダ(find)をpaginateに置き換える。

class HogeController < ApplicationController
  # GET /hoges
  # GET /hoges.xml
  def index
    #@hoges = Hoge.find(:all)
    @hoges = Hoge.paginate :page => params[:page]
    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @hoges }
    end
  end

paginateに渡すハッシュはリクエストに含まれるはずの対象ページ(:page 数値を期待)をページネーションに引き渡すことで、ダイレクトに対象のページにナビゲートが可能だ。

paginate指定可能なパラメタは以下の通り。

:page     対象ページ。必須だがセットされない場合の規定値は1(先頭ページ)
:per_page   ページ中に含まれるモデルの件数。規定値は30(件/ページ)
:total_entries ページネーションの対象とするモデルの総件数。セットしない場合は全件が対象。:countとは排他的に使用する
:count     内部で実行される処理行数の取得処理で実行されるSELECTのCOUNTパラメタの引数として使用される。:total_entriesとは排他的に使用する
:finder    使用されるActiveRecordファインダの名前。規定値は"find"


2. ビューの修正
同じくscaffoldで一覧表示用に生成されたビュー(index.html.erb)にページネーションをナビゲートするリンクを生成するヘルパメソッドを記述する。

<h1>Listing hoges</h1>
<h4><%= will_paginate(@hoges) %></h4>
<table>
  <tr>
  :

このWillPaginate::ViewHelpers::will_paginateメソッドを記述するだけで、以下ようにページをナビゲーションするためのリンクがレンダリングされる。

これは便利だ。
なお、この"<< Previous "や"Next >>"は、同WillPaginate::ViewHelpersのモジュール変数で定義されているが、

@@pagination_options = {
  :class => 'pagination',
  :prev_label => '« Previous', #前ページラベル
  :next_label => 'Next »', #次ページラベル
  :inner_window => 4, #?
  :outer_window => 1, #?
  :separator => ' ', #リンクの間のセパレータ
  :param_name => :page, #ページの制御に使われるパラメタのシンボル名
  :params => nil, #付加するパラメタ
  :renderer => 'WillPaginate::LinkRenderer', #使用されるレンダラ
  :page_links => true, #?
  :container => true #?
}

注釈にある通り、config/initializers/will_paginate.rbというスクリプトを作成し、内部に初期化のためのコードを記述することができる。

早速、それっぽく日本語で書いてみよう。

  • $RAILS_ROOT\config\initializers\will_paginate.rb
WillPaginate::ViewHelpers.pagination_options[:previous_label] = '前へ'
WillPaginate::ViewHelpers.pagination_options[:next_label] = '次へ'

これで完璧と思ったが、このスクリプトを作りサーバを実行するとなぜか以下のエラーになってしまう。

E:/www/addressbook/vendor/rails/activesupport/lib/active_support/dependencies.rb:142:in `load_without_new_constant_marking': E:/www/addressbook/config/initializers/will_paginate.rb:2: Invalid char `\216' in expression (SyntaxError)
E:/www/addressbook/config/initializers/will_paginate.rb:2: Invalid char `\237' in expression
E:/www/addressbook/config/initializers/will_paginate.rb:2: Invalid char `\202' in expression
E:/www/addressbook/config/initializers/will_paginate.rb:2: syntax error, unexpected tIDENTIFIER, expecting $end

久しぶりに大はまりの予感がするな。