ページネーション機能がある一覧表示ページのパンくずリストに、「Xページ目」と表示するための実装方法を紹介します。
テキストだとちょっと伝わりづらいですが、
のように、「1ページ目と2ページ目以降でことなる表示」にし、「2ページ目以降にはページ数を表示する」、ということを今回の仕様とします。
環境
自作のプロテイン口コミサービスに導入( https://github.com/yuki0920/supplebox )のアイテム一覧ページ(/products/index)に導入すること前提に説明します。
また、ページネーション機能はkaminari
で、パンくずリスト機能はgretel
ですでに実装されていることを想定しています。
# Gemfile
gem 'kaminari'
gem 'gretel'
現状
1ページ目でも2ページ目以降でもページ名(アイテム一覧)が表示されています。
gretelのオーソドックスな使い方をしています。
crumb :products do
link 'アイテム一覧', products_path
parent :root
end
- breadcrumb :products
Xページ目を表示する
設定ファイルに追記します。parentにproductsを設定します。ページ数をpageとして第2引数で受け取り、
pageを使ってページ数を表示するようにします。
第2引数で受け取った値を表示できる、というのはREADMEのサンプル集に載っています。
crumb :products do
link 'アイテム一覧', products_path
parent :root
end
# 追記
crumb :products_pagination do |page|
link "#{page}ページ目"
parent :products
end
- breadcrumb :products_pagination params[:page]
呼び出し元のViewテンプレートでは、breadcrumbメソッドの引数に注目です。
- 第1引数に、products_pagenation
- 第2引数に、params[:page]
kaminariでは、ページ数がクエリパラメータとして渡ってきます(例えば、/products?page=2
)ので、params[:page]
でページ数を取得して第2引数として渡すのです。
このようにすることで、1ページ目も2ページ目以降もパンくずリストにページ数を表示することができました。
が、1ページ目のときには問題があります。
params[:page]
がnilのため、Home › アイテム一覧 › ページ目
の表示になってしまいます。
1ページ目と2ページ目以降で場合分けをする
ということで、param[:page]
の値を使って、1ページ目と2ページ目以降で場合分けをします。
- if params[:page].nil? || params[:page] == 1
= breadcrumb :products
- else
= breadcrumb :products_pagination, params[:page]
これで、当初の目標を満たすことができました。
- 1ページ目ならば
ページ名
- 2ページ目ならば
ページ名 > #{ページ数}ページ目
とはいえ、Viewファイルがごちゃっとしているのが気になります。
リファクタリング
ロジックをViewファイルに書くと見通しが悪くなってしまうので、メソッド化してヘルパーに切り出します。
def breadcrumb_pagination
if params[:page].nil? || params[:page] == 1
breadcrumb :products
else
breadcrumb :products_pagination, params[:page]
end
end
呼び出し元もヘルパーに定義したメソッドに修正します。
以上で完了です。
- breadcrumb_pagination
補足(System Spec)
パンくずリストの実装に関して下記のようなテストを書いて仕様を担保しました。
パンくずリストに関わる実装のみを抜粋しているので、雰囲気だけでも伝えられれば。
やはり、テストを書くとリファクタリングがはかどりますね!
# frozen_string_literal: true
require 'rails_helper'
describe 'アイテム', type: :system do
describe '一覧機能' do
before do
create_list(:product, 13)
end
it 'ユーザーはアイテム一覧を閲覧できること' do
visit products_path
expect(page).to have_content 'Home › アイテム一覧'
expect(page).to_not have_content 'Home › アイテム一覧 › 1ページ目'
expect(page).to have_selector '.pagination'
within '.pagination' do
click_link '2'
end
expect(page).to have_content 'Home › アイテム一覧 › 2ページ目'
within '.breadcrumbs' do
expect(page).to have_link 'アイテム一覧' ,href: products_path
end
end
end
end