woshidan's blog

あいとゆうきとITと、とっておきの話。

パンくずリストをURLから自動生成する

意味があるか、どうかじゃない。だけど、書いてみて、正直手動の方が早い気がする。

 

概要

request.urlでいま見ているページのURLを受け取って、そのURLからパンくずリストを生成するためのURLと見出しが組になっている配列を返すための関数郡と、

その返り値を使って、パンくずリストを作っているヘッダー内のスクリプト

 

前提条件 

  • URLが下記に設定したみたいに、サイトの階層構造をそのまま表していること。

ちょっとRESTfulではない。反省。

 

BreadcrumbList::Application.routes.draw do
root 'static_pages#home'
match "/products", to: 'product_categories#index', via: 'get'
match "/products/category/:id", to: 'products#index', via: 'get'
match "/products/category/:category_id/product/:id", to: 'products#show', via: 'get'
match '/personal', to: 'departments#index', via: 'get'
match "/personal/department/:id", to: 'employees#index', via: 'get'
match '/personal/department/:department_id/employee/:id', to: 'employees#show', via: 'get'
end
view raw route.rb hosted with ❤ by GitHub

 

 

階層ごとの文字列を部分url(なんだかディレクトリとはちょっと違う気がした)とする。

  • 部分urlと見出しが一対一に対応すること
  • ある階層で社員一覧(○○課)/社員一覧(xx課)みたいに分岐している場合は、 項目名/値のような連続した二つの部分がセットで一つの階層を表す部分URLになっていること

 

たとえば、department/2って部分URLがあったら、この二つはセットで、

部署番号2番のページに対応する部分URLってする。

 

また、

  • このとき、値は項目を表すidになっていること

URLの取得、設定以外に関係ないけど、Rails 4.0で書いてます。

 実装

メソッド

get_breadcrumbs

request.urlからいま見てるページのURLを受け取って/の区切りに分けます。

そのあと、get_layer_pieciesに投げて部分URLと見出しの配列を受け取って、その値をget_layersに投げて、部分URLを階層ごとのページのURLに直します。最終的に階層ごとのページのURLと見出しの組のハッシュの配列を返します。

def get_breadcrumbs
url = request.url
url_piecies = url.split("/")
url_piecies.slice!(0,2)
url_piecies[0].gsub!(/:/,'')
layer_piecies = get_layer_piecies(url_piecies)
layers = get_layers(layer_piecies)
end
view raw get_breadcrumbs hosted with ❤ by GitHub

get_layer_piecies(url_piecies)

get_layer_captionとget_category_captionを使って、/で区切られた文字列の配列の要素から、部分URLとそれに対応する見出しの組のハッシュを作り、そのハッシュの配列を返します。

部分URLに対応する見出しの取得するとき、get_layer_captionの戻り値がnilなら項目名に対応するidを扱っているのだと判断して、1個前の部分URLや見出しとセットにするようにしてます。

def get_layer_piecies(url_piecies)
layer_piecies = []
url_piecies.each do |url_piece|
layer_caption = get_layer_caption(url_piece)
if layer_caption == nil
category_caption = get_category_caption(url_piece, layer_piecies.last[:url])
layer_piecies.last[:caption] = layer_piecies.last[:caption] + "(#{category_caption})"
layer_piecies.last[:url] = layer_piecies.last[:url] + "/#{url_piece}"
else
url_piece = '/' if url_piece == 'localhost3000'
layer_piecies << { caption: layer_caption, url: url_piece }
end
end
layer_piecies
end

get_layer_caption(url_piece)

辞書のように事前に階層名に相当する文字列と対応する見出しをハッシュに登録しておきます。で、受け取った文字列がそのハッシュのキーとして存在すれば、対応する見出しを、なければnilを返します。

def get_layer_caption(url_piece)
layer_caption = { 'localhost3000' => "管理画面",
'personal' => "部署一覧",
'department' => '部署',
'employee' => '社員',
'products' => '商品カテゴリ一覧',
'category' => 'タイプ',
'product' => '商品'
}
layer_caption[url_piece]
end

get_category_caption(url_piece, category)

項目名を受け取った値をもとにデータベースから取得してます。どの表から検索してくるかはcategoryで決めます。 

def get_category_caption(url_piece, category)
return Department.find(url_piece).name if category == 'department'
return Employee.find(url_piece).name if category == 'employee'
return ProductCategory.find(url_piece).name if category == 'category'
return Product.find(url_piece).name if category == 'product'
end

get_layers(layer_piecies)

部分URLを階層ごとのページのURLに直してます。

def get_layers(layer_piecies)
layers = []
layer_url_piecies = []
layer_piecies.each do |layer_piece|
layer_url_piecies << layer_piece[:url]
end
layer_piecies.each_with_index do |layer_piece, i|
url = layer_url_piecies[0..i].join('/')
url.slice!(0,1) if url != '/'
caption = layer_piece[:caption]
layers << { caption: caption, url: url }
end
layers
end
view raw get_layers hosted with ❤ by GitHub

 

in _header.html.erb

get_breadcrumbsの返り値をもとにパンくずリストを作っている部分

<% breadcrumbs = get_breadcrumbs %>
<% breadcrumbs.each do |breadcrumb| %>
<% class_name = 'breadcrumb'%>
<% class_name += ' last' if breadcrumbs.last == breadcrumb %>
<%= link_to "> " + breadcrumb[:caption], breadcrumb[:url], :class => class_name %>
<% end %>
view raw in_header hosted with ❤ by GitHub

 

説明を書く練習なのだ、練習なのだと思っていても恥ずかしいな、これ。

反省

  • get_category_caption,get_layer_captionのあたりで途中まで書いてちょっとどうしようかなーってなって簡単なもの書くときでも仕様が甘いな、と思った。

説明書いてみたら、これだけのことをするのにこれだけ考えるんだよ、みたいなことが身に付くかと思ったが恥ずかしいな、これ。

  • テスト用データを用意するのに疲れた。rakeファイル使ったり、rakeファイルに入れるデータを用意したりしてたら少し手間だったのでそれでやや満足して作業を中断したり、チュートリアル眺めながらバリデーション書いてたら日が暮れたりした。やりたいのはそこじゃない。