はじめに
本記事は、Ruby on Railsでパンくずリストをシンプルに実装する方法を丁寧に解説します。外部のGemに頼らず、Rails 7.2以降で導入されたコンポーネント機能を活用して、再利用しやすく保守しやすいパンくずリストを作る手順を紹介します。
目的
パンくずリストは利用者の現在地を示し、サイト内の移動を助けます。検索エンジン向けの構造化や、アクセシビリティの向上にも役立ちます。本記事ではこれらの観点を踏まえた実装例を提示します。
想定読者と前提
Railsの基本的な使い方(コントローラやビューの扱い)に慣れている方を対象とします。Rails 7.2以降と、簡単なHTMLの知識があるとスムーズです。
記事の流れ
第2章でパンくずの役割とRailsでの重要性を説明し、第3章以降で実装パターン、コンポーネント化の方法、呼び出し例、パーシャルとの違い、注意点を順に解説します。各章で実例コードを示し、SEOやアクセシビリティに配慮した実装を目指します。
パンくずリストとは?Railsでの重要性
定義
パンくずリスト(Breadcrumbs)は、現在のページがサイト内でどの位置にあるかを示す階層的なナビゲーションです。通常は「ホーム > カテゴリ > サブカテゴリ > ページ」のように表示し、上位のページへ戻るリンクを提供します。
Railsでの重要性
Railsアプリではルーティングやリソース階層が明確なことが多く、パンくずが自然に役立ちます。ユーザーは自分の位置を把握しやすくなり、回遊率が上がります。SEOでも構造化された内部リンクは評価につながります。
具体例
例: Home > Articles > Ruby > 記事タイトル。Articlesの一覧から個別記事へ遷移したとき、階層を示して戻り先を分かりやすくします。
実装の基本方針
- コントローラで階層情報を用意する(@categoryなど)。
- ビューやヘルパーでlink_toとパスヘルパーを使い表示する。
- 共通レイアウトに設置して全ページで使えるようにする。
アクセシビリティとSEO
nav要素にaria-labelを付け、順序を示すolで構成すると良いです。検索エンジン向けに構造化データを付与する方法もあります。
留意点
過度に深い階層は避け、スマホでは短く表示するなどの配慮が必要です。
Railsにおけるパンくずリストの実装パターン
主な実装パターン
- Gemを使う方法(gretel、breadcrumbs_on_railsなど)。設定が楽で細かい表現に向きます。
- パーシャル+ヘルパーで自作する方法。自由度が高く依存を減らせます。
- Railsコンポーネントを使う方法(Rails 7.2以降)。再利用性とテスト性が高まります。
本章の方針
本記事はGemを使わないシンプル実装に注力します。まずはヘルパーでパンくず配列を作り、レイアウトで描画する基本パターンを紹介します。
シンプルな実装例(ヘルパー+レイアウト)
app/helpers/breadcrumbs_helper.rb
module BreadcrumbsHelper
def breadcrumbs(items = [])
items.map.with_index do |(name, path), i|
if path && i < items.size - 1
link_to(name, path)
else
content_tag(:span, name)
end
end.join(" > ").html_safe
end
end
ビューではコントローラやビューで配列を用意して呼び出します。
<%= breadcrumbs([['Home', root_path], ['記事', articles_path], [@article.title, nil]]) %>
動的な項目追加
コントローラで@breadcrumbsをセットしてレイアウトで表示する方法が簡単です。コンポーネントに移行すれば、より整理して再利用できます。
使い分けの目安
- 小規模ならヘルパーで十分。テストや再利用性を重視するならコンポーネントを検討してください。
Railsのコンポーネントでパンくずリストを作る
背景
Rails 7.2ではコンポーネント設計が進化し、localsを明示的に渡す方が推奨されます。これにより、Gemに頼らず柔軟で再利用しやすいパンくずリストを作れます。
基本方針
- items引数にハッシュ配列(labelとhref)を渡す
- ブロックで現在ページのタイトルを出力する
- schema.orgのBreadcrumbListに対応してSEOリッチスニペットを狙う
コンポーネント例(簡略)
class BreadcrumbsComponent < ViewComponent::Base
def initialize(items:)
@items = items
end
end
<nav aria-label="breadcrumb">
<ol itemscope itemtype="https://schema.org/BreadcrumbList">
<% @items.each_with_index do |item, i| %>
<li itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
<a href="<%= item[:href] %>" itemprop="item"><span itemprop="name"><%= item[:label] %></span></a>
<meta itemprop="position" content="<%= i+1 %>" />
</li>
<% end %>
<li aria-current="page"><%= yield %></li>
</ol>
</nav>
呼び出し例
<%= render BreadcrumbsComponent.new(items: [
{label: 'Home', href: root_path},
{label: '記事', href: articles_path}
]) do %>
記事タイトル
<% end %>
ポイント
構造をコンポーネントへ閉じ込めると、ビューがすっきりします。schema.orgの属性は検索結果のリッチ表示に有利です。使い回しやテストも容易になります。
コンポーネントの呼び出し例
概要
呼び出し側では、items配列で階層を表現し、最後の要素(カレントページ)をブロックで出力する実装が分かりやすいです。ここではERBの例と、SEOのためのschema.org(BreadcrumbList)を使ったJSON-LD生成例を示します。
items配列の定義例
- Ruby(コントローラやビュー内):
items = [
{ name: 'ホーム', url: root_path },
{ name: 'カテゴリ', url: categories_path },
{ name: '商品名', current: true }
]
最後の要素にcurrent: trueを付けて、リンクではなくプレーンテキスト(ブロック)で出す合図にします。
コンポーネント呼び出し(ERB)
<%= render BreadcrumbsComponent.new(items: items) do |item| %>
<% if item[:current] %>
<span aria-current="page"><%= item[:name] %></span>
<% else %>
<%= link_to item[:name], item[:url] %>
<% end %>
<% end %>
このようにブロックを渡すと、カスタムな出力(現在ページの強調やマイクロフォーマット付与)が簡単にできます。
schema.org(JSON-LD)でのリッチスニペット対応例
ビューで同じitemsを使ってJSON-LDを生成します。簡潔な例:
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
<% items.each_with_index do |it, i| %>
{
"@type": "ListItem",
"position": <%= i + 1 %>,
"name": "<%= j it[:name] %>",
"item": "<%= it[:url] || request.original_url %>"
}<%= ',' unless i == items.size - 1 %>
<% end %>
]
}
</script>
current:trueの要素はitemにURLがない場合が多いので、itemにrequest.original_urlを使って現在ページを入れる方法を示しています。
補足(アクセシビリティ)
- 現在ページにはaria-current=”page”を付けます。
- リスト構造(nav > ol > li)にして、スクリーンリーダーで追いやすくします。
この呼び出しパターンは、見た目のカスタマイズやSEO対応を分離して扱えるため、保守が楽になります。
パーシャルとの違い・メリット
概要
パーシャルは従来の部分テンプレートで、柔軟にHTMLを切り出せます。一方、コンポーネントは表示ロジックとインターフェイスを明確に分けて扱えます。Rails 7.2以降はlocalsを明示でき、引数の期待値が分かりやすくなりました。
インターフェイスの明確さ
パーシャルだと渡す変数名が暗黙になりやすく、どの値が必須か分かりにくいです。コンポーネントは初期化時に引数を受け取り、必須項目やデフォルト値をコード上で示せます。たとえば、itemsが必須でtitleにデフォルトを設定する、といった記述が可能です。
再利用性とテストのしやすさ
コンポーネントは単体で呼び出せるため、ビュー以外からの再利用や単体テストが容易です。パーシャルはビューの文脈に依存しやすく、切り出し先での前提条件を追う必要があります。
可読性と保守性
コンポーネントはインターフェイスが明示されるため、チームでの受け渡しや変更時の影響範囲が追いやすくなります。コードレビューでも意図が伝わりやすいです。
パフォーマンスと実装負荷
小規模なら差は少ないですが、大規模アプリではコンポーネントの明示的な設計が最適化やキャッシュ管理に役立ちます。ただし、導入時は構造の見直しが必要です。
実用例(簡易)
- パーシャル: render ‘breadcrumbs’, items: @items
- コンポーネント: render BreadcrumbComponent.new(items: @items)
以上の点から、明確なインターフェイスと再利用性を重視する場合にコンポーネントを選ぶと運用が楽になります。
実装時の注意点・カスタマイズ
配列(items)の生成場所と注意
パンくず用の配列(items)はコントローラーで作るか、ヘルパーで生成できます。コントローラーで作るとルーティングやアクションに依存した値を簡単に渡せます。ヘルパーにすると共通処理をまとめられます。例:showアクションでは親カテゴリを先に入れるなど順序に注意してください。












