Railsメモ - paginateを任意のSQLで - その2
さっきの、任意のSQLでpaginateする件、もうすこしマシなやりかたに落ち着いたので書いておく。
paginate_by_sqlはすばらしいアイデアなのだが、SQL文をcontroller中に書くハメになるのが玉にキズ。
やはり、SQLはmodelの中に閉じこめておきたいのが人情というものだ。
そこで、finderとcounterをlambdaで指定して、こんな使い方のできる汎用メソッド(paginate_by_finder_and_counter)を書いてみた。
@question_pages, @questions = paginate_by_finder_and_counter(lambda { |offset, limit| Question.find_with_category_id(category_id, offset, limit) }, lambda { Question.count_with_category_id(category_id) }, :per_page => 5)
ソースはこんなだ。
def paginate_by_finder_and_counter(finder, counter, options={}) ::ActionController::Pagination.validate_options!(:entry, options, true) page = params[options[:parameter]] count = counter.call paginator = ::ActionController::Pagination::Paginator.new(self, count, options[:per_page], page) collection = finder.call(paginator.current.offset, options[:per_page]) return paginator, collection end
まとめると、
1. modelにoffsetとlimitを指定できるfinder methodを用意する。
2. modelにデータ件数を返すcounterメソッドを用意する。
3. controllerの中から、paginate_by_finder_and_counterを呼んで、finderメソッドとcounterメソッドをlambdaで指定する。
4. 普通にpageデータをviewの中から呼ぶ。
昨日の俺paginateメソッド(以下)とくらべると、このほうが大分いいと思うな。
@question_pages, @questions = paginate_questions_with_category_id(1, :per_page => 5) ... def paginate_questions_with_category_id(category_id, options={}) ::ActionController::Pagination.validate_options!(:question, options, true) page = params[options[:parameter]] count = Question.count_with_category_id(category_id) paginator = ::ActionController::Pagination::Paginator.new(self, count, options[:per_page], page) collection = Question.find_with_category_id(category_id, paginator.current.offset, options[:per_page]) return paginator, collection end