ActiveRecord (3.0.9) で group by を使いつつ will_paginate (3.0.pre4) でちゃんとページネーション

ActiveRecordは3.x系になってからQuery Interfaceというより抽象的にSQLを構築できるメソッド群が加えられた。

groupSQLGROUP BY句を構築するメソッドで引数にグループ化する行を渡す。

またcountは条件に該当する列の件数を数え上げる。

ActiveRecord 3.xではgroupメソッドを使ってグループ化すると、countメソッドがグループ化に使われた列をキーに、キーごとの行の件数を値に持つハッシュを返すようになる。余計なお世話である。同じcountというインターフェースを介して異なる種類の値を返すというのは狂っている。

ところでwill_paginateはモデルを拡張してpaginateというページネーションを実現するメソッドなどを定義する。ページネーションには「コレクションの総件数」「1ページに表示するコレクションの件数」「総ページ数」などのパラメータが必要で、will_paginateでは「コレクションの総件数」を取得するのにcountメソッドを呼んでいる。

ActiveRecord 3.xとwill_paginate 3.0.pre4の組み合わせでかつgroupメソッドを使ってグループ化したコレクションに対してページネーションをしようとするとエラーになる。GitHubにあるバージョンでは既に修正されているけど、3.0.pre4を使うプロジェクトなのでどうしようもない。

paginatetotal_entriesオプションをとるはずだけど渡しても見てくれない。なので、WillPaginate::Collectionに対して直接total_entriesを設定する。

User.group(:age).paginate(:page => params[:page], :per_page => 10).tap {|_| _.total_entries = User.select('distinct age').count }

非常にダサいので最新版を使おう……。