11月 26 2008
acts_as_taggable_on_steroids と will_paginate を同時に使う
Rails2 で acts_as_taggable_on_steroids でタグ付けしたモデル(ここでは Entry とする)のリストを will_paginate で paginate する方法。
以下のようにすると、全該当 Entry を find(:all) してしまうので、精神衛生上いまいち。(ということにしておく)
Entry.find_tagged_with('rails').paginate(:page => params[:page], :per_page => 30)
find(:all) することなしに、こんな風に書けるようにするには。
@pages = Entry.paginate_tag 'rails',
:page => params[:page],
:per_page => 30
lib/paginate_tag.rb をこんな内容で作り、environment.rb で読み込む。
module ActiveRecord
module Acts #:nodoc:
module Taggable #:nodoc:
module SingletonMethods
def count_tagged_with(name, *args)
options = find_options_for_find_tagged_with(name, *args)
options.delete :select
# この辺はもうちょいスマートにいけないかな?
options.delete :page
options.delete :per_page
options.delete :total_entries
count(options)
end
def paginate_tag(name, *args)
count = count_tagged_with(name, *args)
options = args.last.is_a?(Hash) ? args.pop.symbolize_keys : {}
paginate_tagged_with(name, {
:per_page => 30,
:total_entries => count,
}.merge(options))
end
end
end
end
end
ただしこのやり方では find(:all) はしないかわりに COUNT (*) クエリを別途呼んでしまうので諸刃の剣。どっちが速いかは場合によるだろう。
ていうか cache_fu してしまえば一緒なのかも。(要追試。)
will_paginate は paginate_xxx メソッドを呼ぶと内部で find_all_xxx を使ってくれるのだが、素直に paginate_tagged_with するだけだと、count の正しい値が取れない。というか count の値を正しく取れることはあるんだろーか…。
