ActiveRecordは3.x系になってからQuery Interfaceというより抽象的にSQLを構築できるメソッド群が加えられた。
group
はSQLのGROUP 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を使うプロジェクトなのでどうしようもない。
paginate
はtotal_entries
オプションをとるはずだけど渡しても見てくれない。なので、WillPaginate::Collectionに対して直接total_entries
を設定する。
User.group(:age).paginate(:page => params[:page], :per_page => 10).tap {|_| _.total_entries = User.select('distinct age').count }
非常にダサいので最新版を使おう……。