Railsでページネートと言えばkaminariで、インストールも簡単ですが、JSONに件数とか入るようになってなかったので、もっとも簡単な方法を試行錯誤したので、メモしておきます。
結論は、viewsのindex.json.jbuilderを直すだけで、良い感じになりました。
日本語はkaminari-i18nを利用。
kaminariインストール
Gemfileの最終行に追加
# Use kaminari gem 'kaminari' gem 'kaminari-i18n'
$ bundle install $ rails g kaminari:config create config/initializers/kaminari_config.rb $ rails g kaminari:views default create app/views/kaminari/_next_page.html.erb create app/views/kaminari/_last_page.html.erb create app/views/kaminari/_first_page.html.erb create app/views/kaminari/_page.html.erb create app/views/kaminari/_paginator.html.erb create app/views/kaminari/_prev_page.html.erb create app/views/kaminari/_gap.html.erb
変更可能にする為、翻訳ファイルをgemの中からコピー
$ cp ~/.rvm/gems/ruby-2.6.3/gems/kaminari-i18n-0.5.0/config/locales/ja.yml config/locales/kaminari.ja.yml
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/e39139cd3660cb4c272cc2886adee9eb70694376
kaminariの使い方
app/controllers/spaces_controller.rb での例
変更前
def index @spaces = Space.all end
変更後
def index @spaces = Space.order(created_at: 'DESC', id: 'DESC').page(params[:page]).per(Settings['default_spaces_limit']) end
並び順(order)は、DBに依存する場合もあるので、必ず一意になるようにidも加えた方が良い。(検証や問題があった時の再現がし易い)
表示数(per)は未指定なら、config/initializers/kaminari_config.rbの設定が使われるが、機能によって変えたい場合も多いし、ベタ書きは良くないのでconfig(gem)に定義。
config/settings.yml
default_spaces_limit: 25
app/views/spaces/index.html.erb に下記を追加。
<p><%= page_entries_info @spaces %></p>
<p><%= paginate @spaces %></p>
JSONページネート対応
app/views/spaces/index.json.jbuilder での例
変更前
json.array! @spaces, partial: 'spaces/space', as: :space
変更後
json.total_count @spaces.total_count json.current_page @spaces.current_page json.total_pages @spaces.total_pages json.limit_value @spaces.limit_value json.spaces do json.array! @spaces end
partial消したので、app/views/spaces/_space.json.jbuilder も削除
http://localhost:3000/spaces.json の出力結果を整形。良い感じですね。
{ "total_count": 26, "current_page": 1, "total_pages": 2, "limit_value": 25, "spaces": [ { "id": 26, "subdomain": "myspace26", "name": "マイスペース26", "created_at": "2020-05-25T09:50:48.884+09:00", "updated_at": "2020-05-25T09:50:48.884+09:00" }, <省略> { "id": 2, "subdomain": "myspace2", "name": "マイスペース2", "created_at": "2020-05-25T09:50:48.604+09:00", "updated_at": "2020-05-25T09:50:48.604+09:00" } ] }
テスト追加
多いので抜粋して書きます。実際には、contextからit_behaves_likeで、
下記のshared_examples_forを呼び出してあげる必要があります。
spec/requests/spaces_spec.rb
shared_examples_for 'ベースドメイン、1ページ、1番新しいスペース' do it '(json)名前が一致する' do get spaces_url, headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[0]['name']).to eq(@create_spaces[@create_spaces.count - 1].name) end it '(json)サブドメインが一致する' do get spaces_url, headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[0]['subdomain']).to eq(@create_spaces[@create_spaces.count - 1].subdomain) end end shared_examples_for "ベースドメイン、1ページ、#{Settings['default_spaces_limit']}番目に新しいスペース" do it '(json)名前が一致する' do get spaces_url, headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[Settings['default_spaces_limit'] - 1]['name']).to eq(@create_spaces[@create_spaces.count - Settings['default_spaces_limit']].name) end it '(json)サブドメインが一致する' do get spaces_url, headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[Settings['default_spaces_limit'] - 1]['subdomain']).to eq(@create_spaces[@create_spaces.count - Settings['default_spaces_limit']].subdomain) end end shared_examples_for "ベースドメイン、2ページ、#{Settings['default_spaces_limit'] + 1}番目に新しいスペース" do it '(json)名前が一致する' do get spaces_url(page: 2), headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[0]['name']).to eq(@create_spaces[@create_spaces.count - (Settings['default_spaces_limit'] + 1)].name) end it '(json)サブドメインが一致する' do get spaces_url(page: 2), headers: base_headers.merge(json_headers) response_spaces = JSON.parse(response.body)['spaces'] expect(response_spaces[0]['subdomain']).to eq(@create_spaces[@create_spaces.count - (Settings['default_spaces_limit'] + 1)].subdomain) end end shared_examples_for 'ベースドメイン' do it '(json)total_countが一致する' do get spaces_url, headers: base_headers.merge(json_headers) expect(JSON.parse(response.body)['total_count']).to eq(@create_spaces.count) end it '(json)1ページ、current_pageが一致する' do get spaces_url, headers: base_headers.merge(json_headers) expect(JSON.parse(response.body)['current_page']).to eq(1) end it '(json)2ページ、current_pageが一致する' do get spaces_url(page: 2), headers: base_headers.merge(json_headers) expect(JSON.parse(response.body)['current_page']).to eq(2) end it '(json)total_pagesが一致する' do get spaces_url, headers: base_headers.merge(json_headers) expect(JSON.parse(response.body)['total_pages']).to eq((@create_spaces.count - 1).div(Settings['default_spaces_limit']) + 1) end it '(json)limit_valueが一致する' do get spaces_url, headers: base_headers.merge(json_headers) expect(JSON.parse(response.body)['limit_value']).to eq(Settings['default_spaces_limit']) end end
【参考】ここまでのコミット内容
https://dev.azure.com/nightonly/rails-app-origin/_git/rails-app-origin/commit/f617c93953699f2e190f11bee6ecab0b71d02fca