kaminariを使って外部APIのページネーションをする

外部のAPIから取得したデータをkaminariを使ってページングするときのメモです。

結論

kaminariのpaginate_arrayメソッドに、以下のように配列とtotal_countを指定することでできる。

@posts = Kaminari.paginate_array(配列, total_count: 総数)
  .page(現在のページ)
  .per(各ページ毎の表示数)

具体例

今回は、jsonを出力するAPIを用意し、そのjsonをパースしてページネーションをするということをします。

API

投稿一覧を出力するだけのシンプルなAPIを作成します。 こちらもKaminariをインストール済みとします。

コントローラー

class PostsController < ApplicationController

  def index
    @posts = Post.published.page(params[:page]).per(1)

    respond_to do |format|
      format.html { render :index }
      format.json { render 'index.json.jbuilder' }
    end
  end

end

ビュー(jbuilder

json.meta do # kaminariのメソッド
  json.total_pages @posts.total_pages
  json.current_page @posts.current_page
  json.total_count @posts.total_count
  json.limit_value @posts.limit_value
end
json.data do
  json.array! @posts do |post|
    json.id post.id
    json.title post.title
  end
end

json

以下のようなjsonが出力されます。

{
  "meta":{
    "total_pages":2,
    "current_page":1,
    "total_count":2,
    "limit_value":1
  },
  "data":[
    {
      "id":1,
      "title":"タイトル1",
    }
    {
      "id":2,
      "title":"タイトル2",
    }
  ]
}

ページネーション

コントローラー

class ExternalPostsController < ApplicationController

  def index
    require 'net/http'
    require 'uri'
    require 'json'

    end_point = "https://sample.com/posts.json?page=#{params[:page]}"
    uri = URI.parse(end_point)
    response = Net::HTTP.get_response(uri)
    body = JSON.parse(response.body)
    meta = body["meta"]

    @posts = Kaminari.paginate_array(body["data"], total_count: meta["total_count"])
      .page(meta["current_page"])
      .per(meta["limit_value"])
  end
end

ビュー

- @posts.each do |post|
    # postを表示する処理
- end

= paginate @posts