[memo]パンくずリストについて

#Rubyの gem 'gretel' を利用してパンくずリストを作成する場合の注意点と考え方

フリマアプリにおいて、「topページ＞商品詳細ページ＞商品購入ページ」とページ遷移する場合にページ上部にパンくずリストを追加したいと思い実装していました。途中、なぜ、そのような記述が必要かわからなくなった部分がありましたので個人メモとしてまとめておきます。

##実装手順
###gem 'gretel' の導入

```ruby
# Gemfile
gem 'gretel'

# ターミナル
$ bundle install
```

###パンくずを記載したいviewへ設置
```html:layouts/application.html.erb
<body>
  <%= breadcrumbs separator: " &rsaquo; " %>

#省略
#省略
#省略

</body>

```
layouts/application.html.erbに記述することで配下のviewファイルにも反映されます。今回はページ上部に表示させるため、\<body>の最上部に配置します。``separator: " &rsaquo;”``は、パンくず間の区切りである「>」を示します。``class: "breadcrumbsList"``などを追記すればCSSを使ってスタイルの変更が可能です。

####各viewファイルの編集

```html:各viewファイル
#それぞれのファイルにおいて表示したい箇所へ記述します
#breadcrumb :/breadcrumbs.rb/で設定した、ページ名を記述

# topページ：items/index.html.erb
<% breadcrumb :root %>

# 商品詳細：items/show.html.erb
<% breadcrumb :items %>

# 商品購入：purchases/index.html.erb
<% breadcrumb :purchases %>
```
viewの準備は完了です。

###パンくずの親子関係を設定するファイルを作成

```ruby
# ターミナル
$ rails g gretel:install
```


* config/breadcrumbs.rb　が作成されます。<br>``crumb :xx do ... end``の「do」と「end」の間に、アクセスしたいビューのパスや親要素を指定します。次のような記述になります。

```ruby:例
#どこになんの記述をするか
crumb "現在のページ名:ディレクトリ（表示させるビューにもページ名記述）" do
  link "パンくずリストでの表示名", "アクセスしたいページのパス"
  parent :親要素のページ名（前のページ）
end

#実際の記述例
crumb :root do
  link "トップページ", root_path
end

crumb :tweets do
  link "ツイート一覧", tweets_index_path
  parent :root
end

crumb :contacts do
  link "コンタクト", contacts_index_path
  parent :tweets
end

```

###パンくず作成
実際にパンくずを定義していきます。
今回作成したいのは　topページ＞商品詳細ページ＞商品購入ページ　というパンくずです。

####例に習いパンくずを定義

```ruby:config/breadcrumbs.rb
crumb :root do
  link "トップページ", root_path
end

crumb :items do
  link "商品詳細", item_path(item.id)
  parent :root
end

crumb :purchases do
  link "商品購入", item_purchases_path(item.id)
  parent :items
end
```
itemごとにidがありますので、パスには``(item.id)``が必要であると考えました。
するとエラーになりました。

![err01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1012639/90af2543-3504-d4af-d7ee-86bcbeb8379e.png)


itemが定義されていませんよというエラーになりましたのでitemの定義を行いました。

####item定義
```ruby:config/breadcrumbs.rb
crumb :root do
  link "トップページ", root_path
end

crumb :items do
  item = Item.find(params[:id])
  link "商品詳細", item_path(item.id)
  parent :root
end

crumb :purchases do
  item = Item.find(params[:item_id])
  link "商品購入", item_purchases_path(item.id)
  parent :items
end
```

①top > 商品詳細 にはidが必要で、②商品詳細 > 商品購入 にはitem_idが必要と考え上記のような記述をしてみました。①のページ遷移は成功！順調かと思いきや②に遷移しようとした際にエラーが出現しました。

###エラーの解消（仮説と実際に行ったこと）

![err02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1012639/e7ebcb33-c378-4121-c905-c3268b461eb7.png)

itemの情報取得がうまくいってなさそう。そもそも商品詳細から商品購入へのページ遷移を実現したいのに、なぜ``商品詳細``のコードでエラーが出てしまうのか？試しに``[:id]を[:item_id]``に書き換えると商品購入へのページ遷移に成功しました。

```ruby:config/breadcrumbs.rb
#省略
#次のように書き換えました

crumb :items do
  item = Item.find(params[:item_id])
  link "商品詳細", item_path(item.id)
  parent :root
end

#省略
```

無事、商品購入ページには遷移できました。理由がわからない。。。

![ok1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1012639/7ccf2114-a5d3-5f3b-fc8b-3fc1cbe19ac0.png)

しかしこのままだとパンくずリストのリンクから商品詳細にもどるときにまたエラーが出現してしまいます。params[:item_id]とする場合とparams[:id]とする場合があるということは情報分岐が必要？という仮説は立てられましたが、なぜそれが必要かが理解できませんでした。

ページ遷移に気を取られてしまい、すっかり頭から抜けてましたが、今回の実装は``Rubyの gem 'gretel' を利用してパンくずリストを作成する``ということです。それはつまり、gem 'gretel'を使うことによって``ページ上部のhtmlを生成してくれる``を実現するということです。

例えば、gemを利用せず各ページにhtmlを直書きする場合、商品詳細ページには"topページへのリンク先"があり商品購入ページには"topページ"と"商品詳細ページ"のリンク先を記載すると思います。gem 'gretel'を使えばこれを記述せず指定箇所へ生成してくれているのです。作成したフリマアプリでは商品テーブルitemsと購入テーブルpurchasesを別々に作成しています。なので送られてくるparamsの値によって生成するurlを変えなければいけません。

###【完成】条件分岐を記述

```ruby:config/breadcrumbs.rb
crumb :root do
  link "トップページ", root_path
end

crumb :items do |item|
  if params[:item_id] == nil
    item = Item.find(params[:id])
  else
    item = Item.find(params[:item_id])
  end
  link "商品詳細", item_path(item.id)
  parent :root
end

crumb :purchases do |item|
  item = Item.find(params[:item_id])
  link "商品購入", item_purchases_path(item.id)
  parent :items
end

```

上記の記述でページ遷移もhtml生成も問題なく動きました。
生成されたurlは次の通りです。

①商品詳細ページにtop > 商品詳細 のリストを作成⇨idが必要
``item = Item.find(params[:id])``

```html:生成されたhtml
<div class="breadcrumbs">
 <a href="/">トップページ</a>
 <span class="current">商品詳細</span>
</div>
```

②商品購入ページにtop > 商品詳細 > 商品購入 のリストを作成⇨item_idが必要
``item = Item.find(params[:item_id])``

```html:生成されたhtml
<div class="breadcrumbs">
 <a href="/">トップページ</a>
 <a href="/items/11">商品詳細</a>
 <span class="current">商品購入</span>
</div>
```

![order.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1012639/56dc3eee-6c7d-7721-4b0b-75ec9e8b5da1.png)

今回、何を実現したいかを見失ってしまい、解決までかなりの時間がかかってしまいました。
自分が今どういう機能を実装しているか、そのためにどんな記述が必要なのかしっかり考えながら取り組んでいきます。この記事がどなたかの参考になると嬉しいです。