kaminari-sinatraのActiveRecord部分だけを使うという方法もある
2016-10-19
Techこのブログも記事が増えてきたので、ページネーションを実装した。(そう、今までは http://yhara.jp にアクセスすると全部の記事がレンダリングされる仕様だったのである)
Railsでページネーションといえばkaminari gemであるが、Sinatraにも対応していて、kaminari-sinatraというgemがある。
発生したエラー
…のだが、使ってみて困ったことが分かった。paginateヘルパを呼ぶと以下の箇所で「logger.debugは引数を1つしか取らないよ」というエラーが出るのである。
padrino-helpers-0.13.3.2/lib/padrino/rendering.rb in cache_template_path
logger.debug :template, began_at, path[0] if path && logging
kaminari-sinatraはpadrino-helpersに依存しているのだけど、padrinoが期待するloggerのインターフェイスがこのブログで使っているRuby標準のLoggerと違うようなのだ。
対策
どうしようかなと思ったが、そもそもKaminariを使ってやりたかったのは「次のページ」「前のページ」リンクを生成することで、paginateヘルパを使う予定はない。であれば、その部分だけ自前で実装するのでも良いかも、と思ってやってみたのがこちら。
解説
まずkaminari/sinatraをrequireする。READMEにも書いてあるようにこの時点ではActiveRecord部分だけが有効になっている。
require 'kaminari/sinatra'
次にActiveSupportからファイルを1つrequireする(あとで使う)。
require 'active_support/core_ext/object/to_query'
ビュー用のヘルパとして、前後のページへのpathを返すメソッドを定義する。
helpers do
def previous_page_path(scope, params={})
return nil if scope.first_page?
query = params.merge(page: scope.prev_page)
return env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}")
end
def next_page_path(scope, params={})
return nil if scope.last_page?
query = params.merge(page: scope.next_page)
return env['PATH_INFO'] + (query.empty? ? '' : "?#{query.to_query}")
end
end
scopeにはKaminariのpageメソッドの結果を渡す。例えば以下の@postsのような。
@posts = Post.order(datetime: :desc).page(params[:page]).per(10)
ビューはこんな感じ (実際はslimで書いていますがslim読めない人もいると思うのでerbにしています)
<% unless @posts.first_page? %>
<a href="<%= previous_page_path(@posts)) %>">
« Prev
</a>
<% end %>
<% unless @posts.last_page? %>
<a href="<%= next_page_path(@posts)) %>">
Next »
</a>
<% end %>
まとめ
- 前後のページへのリンクを貼るだけなら、KaminariのActiveRecord部分だけ使ってもそんなに手間でない
- Padrinoのloggerの件は悩ましい
- 解決するとしたらkaminari-sinatraをkaminari-sinatraとkaminari-padrinoに分けて、前者はpadrino-helpersに依存しないようにするとかですかねぇ