Hatena::Grouprails

ayucat on Rails

Limited IDs Eager Loadingのとりこです。

2008-08-18はいはい、お盆は終わったよ、さーさー働け働けっ!!!

2008年夏、なぜwill_paginateがモテるのか?

Rails 2.0.2が出て既に3四半期が経とうとしている(2007年12月リリース)。

ということはそれ以後に作られてきたRailsアプリは従来のpaginate(classic paginate)を使うことはなく、

  • will_paginate
  • paginator
  • pagination_find

あたりを使ってがしがしと開発されていったはずだ。

その数、およそ3,000アプリだ。

ayucat独自脳内調査によれば。

でも、あながち間違いじゃなかろう。

Web系エンジニアって日本だけでも数万人はいる(よね?)って想像しているし、そのうちのPerl/PHP/Python/Rubyを使ってる人でも一万人はいるでしょ!!!

というワケで、3,000アプリ or moreとしておく。

controller側の対応

さて、Rails 1.2で教科書やREADMEの通り、こう書いていただろう:

class ItemController < ApplicationController
  #...

  def list
    @item_pages, @items = paginate(:items, :conditions => 'available = 1', :order => 'pref ASC', :per_page => 10)
  end
end

will_paginationでは、

class ItemController < ApplicationController
  #...

  def list
    @items = Item.paginate(:page => params[:page], :conditions => 'available = 1', :order => 'pref ASC', :per_page => 10)
  end

と書こう。

ここで、注意したいのはpaginateの第一引数の:pageキーの値。ページ番号を使うクエリパラメータpageでなかった場合は、それに合わせよう。直さなくてもいい場合が大半だけれども、直す場合はpになっている例が一番多いかな。

view側の対応

<%= pagination_links(@items) %>

あるいは前へ次へだけを表示したくて、

<%= link_to('前へ', :page => @item_pages.current.previous) if @item_pages.current.previous %>
<%= link_to('次へ', :page => @item_pages.current.next) if @item_pages.current.next %>

とこれまた教科書どおりに書いていたかもしれない。

前者の場合は、

<%= will_paginate(@views) %>

とだけ書けばいい。

「前へ」「次へ」の場合は、

<%= will_paginate(@views, :page_links => false) %>

とちょっと書き換えるだけ。これで97%の場合に対応できるはずだ。残りの3%のようなマニアックな依頼者は世の中には存在するのだけれども、めんどくさいと片付けてしまうのが一番幸せだし、世の中のためだろう。そうは言ってられないぜ、生活が、、、というあなたでも、既に用意されている細かいオプションを使えばよい。

最後に―私が一番書きたかったのが、これなのだけど―、何件あって、そのどれを表示しているかを伝える

<%= @item_pages.item_count %> 件中
<%= @item_pages.current_page.first_item %>~<%= @item_pages.current_page.last_item %> 件を表示

これ。

last_item.number(last_item.to_s)に対応するのが分かんなくて、困ったから、そこは自分で計算するようにしてしまった><

というワケで私の解答はこれ:

<%= @items.total_entries %> 件中
<%= @items.offset + 1 %>~<%= [@items.offset + @items.per_page, @items.total_entries].min %> 件を表示

ちゃんと用意されてる気がするんだけど、時間内に見つからなかったから、これで凌ぎました、というコード。

大なり小なり、こういう蓄積が溜まっていくから、Railsアプリはエレガントさを欠くんだよな、、、と思いながら。

まとめ

  1. Rails 1.x時代のpagination (classic pagination)は瞬間的にwill_paginateに移行できるよ(いわゆる秒殺)。
  2. classic paginationを使ってベタベタにview周りを書いている場合でも、かなり簡単に移行できるよ。
  3. classic paginationでがりがり:include, :joinsチューニングされているアプリでも、Rails 2.1.0から導入されたnamed scopeを使えば、そこそこ手軽に移行できるはずだよ。
  4. last_itemの代わりをもうちょっとエレガントに書けるはずだろう。なので、誰か指摘してください><

「classic paginationでがりがり:include, :joinsチューニングされているアプリ」って何それ?って人は今後書くので、楽しみに待ってください^^

トラックバック - http://rails.g.hatena.ne.jp/ayucatch/20080818