近&況

Recent Posts
Edit

kaminari-sinatraのActiveRecord部分だけを使うという方法もある

2016-10-19

このブログも記事が増えてきたので、ページネーションを実装した。(そう、今までは 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)) %>">
    &laquo; Prev
  </a>
<% end %>
&nbsp;
<% unless @posts.last_page?  %>
  <a href="<%= next_page_path(@posts)) %>">
    Next &raquo;
  </a>
<% end %>

まとめ