2005-04-22 (Fri) [長年日記]
_ pagination
Webアプリケーションでは、リストが長くなった時に複数ページに分けて、 「次へ」「前へ」のようなナビゲーションを行うことが多い。 たとえば、Googleの検索結果みたいな。
これって結構面倒なのだが、Railsではpaginateというメソッドによって 簡単に実装できる。
まずは、コントローラ側のコードに、
def list @question_pages, @questions = paginate(:question, :per_page => 5, :conditions => "category_id = 1", :order_by => "date desc") end
のように書いておく。
paginateの第一引数にはモデルの名前*1、 第二引数には以下のようなオプションを指定できる。
- class_name
- モデルのクラス名
- per_page
- 一ページあたりの行数
- conditions
- where句
- order_by
- order by句
- join
- join句
- parameter
- ページ番号を指定するためのパラメータの名前
で、テンプレートに、
<ul> <% for question in @questions %> <li><%=h question.message %> <% end %> </ul> <%= link_to "前へ", { :page => @question_pages.current.previous } if @question_pages.current.previous %> <%= link_to "次へ", { :page => @question_pages.current.next } if @question_pages.current.next %>
と書いておけば、後は勝手にやってくれる。これはラクだなあ。
*1 :foo_barみたいな指定から適当にFooBarのようなクラス名に変換されるらしい
_ pagination with ajax
さらに、ajaxによるpaginationもできるらしい。 こっちは試してないけど。
_ 速度
あまり他の人の参考にはならないけど、手元の「自前なんちゃって フレームワーク+mod_ruby」なプログラムにくらべて、ほぼ同等 (ちょっと機能は劣る)の「Rails+FastCGI」なプログラム(もちろんproduction環境) は二倍くらい遅かった。
普通ならぜんぜん問題ないんだけど、今回はちょっとスピードがいるんだよな。 どうしよう。
ちなみに、
FastCgiConfig -maxClassProcesses 10 -maxProcesses 50 -minProcesses 5
のような設定なのにプロセスが一つしか動いてなかったので、たんにチューニング できてないだけという可能性も高いけど。
ただ、Rails+mod_rubyはRails+FastCGIよりさらに二倍ほど遅かった (DBのコネクションを使い回してなかったりする?)ので、FastCGIのせいではないかも。
あるいは、アプリケーションの処理が軽ければ軽いほど、FastCGIのオーバーへッドが 効いてくるということはあるかもしれない。
_ 高速化
プロファイルを取ると、PGconn#execとModule#public_instance_methodsが 上位に来ていた。 前者に関しては、クエリの結果をキャッシュすることでクエリの発行を減らし、 後者に関しては、AppliationController#action_methodsを以下のように再定義して 高速化。
class MyController < AppliationController ... @@action_methods = public_instance_methods - hidden_actions def action_methods return @@action_methods end end
これで、自前フレームワーク+mod_rubyの1.5倍程度の実行時間に収まった。 実際には、DBのレコードが増えるともっと差は縮まるだろう。
あと、pagenateは、
select count(*) from foo where bar = 1 select * from foo where bar = 1 order by baz limit 5 offset 0
のように2回SQLを発行するようだが、
select * from foo where bar = 1 order by baz limit 6 offset 0
のように「1ページあたりの行数 + 1」行分をlimitで指定すれば、 「次へ」を表示するべきかどうかがわかるから、クエリの発行を1回で 済ませることができそうだ。
ページ数を表示したり、Googleみたいに各ページへのリンクを表示したり するとなると、また話が違って来るが。
文字指向の処理が、jcodeライブラリなんですよねぇ。<br>encodeとかencodingとか、そんな名前に変えたいなぁ。<br>メソッド名もjlengthとかでなく、char_lengthに。
というか、m17n化を:)
まじめにm17n化しようと思ったら、まず$KCODEをm17n化しないといけなさそうな・・・^^;;<br>UTF-8に対応すればおっけ〜♪なら楽なのでしょうが。
実はすでにまつもとさんがブランチで一度作業されています。<br>1.7のころがベースなので、すぐにはマージできませんけど:(