11月 26 2008

acts_as_taggable_on_steroids と will_paginate を同時に使う

Published by HoLY at 1:44:28 under tech

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 の値を正しく取れることはあるんだろーか…。

Tags: , ,

No responses yet

Trackback URI | Comments RSS

Leave a Reply