前書き
app/views/layout/application.html.haml を見返してみると、ページタイトル部に以下の記述を見つけた。
%title= content_for?(:title) ? yield(:title) : “webcit3”
調べてみるとテープレート内に :title というコンテンツがあれば、それを yield してくれるとのこと。これは、いろんなことに使えそうだと早速リファクタリングする。
まずは、すでに実装されているタイトル表示の問題を修正する。問題の一例をここに示す。現在、teacher/years#index は、年度一覧を表示するものであり、その
ページタイトルはそのまま「年度一覧」と記載している。ただし、このページでは年度の変更処理しかしないので、teacher/kyoumus#index からのリンクは「年度変更」と記載している。旧システムではこのようにページごとに表記が乱れていた。
locale の設定
この問題を解決するために、今回作成しているシステムでは、このようなタイトル部分などにlocale を使用することにした。今回は、ページのタイトルの locale をまとめた config/locales/views/titles/ja.yml というファイルを作成し、以下のように記載する(この部分は後日修正する)。
ja: views: teacher_years: index: title: 年度変更
view の修正
app/views/teacher/years/index.html.haml の先頭を以下のように修正する。ここでは、:title に相当する content_for を用意する。先に書いた layout ファイルからこの部分がメソッドとして呼ばれることになる。実際にページタイトルを記述するとき再度呼ぶのも莫迦らしいので、@title にキャッシュしておく。また、ページ内のタイトル表示である %h1 は消しておく。
- content_for :title do = @title = page_title
%h1 を消したのは、ページのタイトル表示である %h1 はほとんどのページで記載するはずだからである。そうであればその記述は、app/views/layout/application.html.haml に記載すればよい。該当部は以下のようになる。%h1 の記載が必要ないページであれば、contnt_for の中で @title に代入しなければよい。このため、%h1 は以下のように layout に移行した。
.container-fluid -if @title %h1= @title = yield
page_title の実装
page_title は自分自身のパスから locale を引き出すメソッドである(このメソッドは後日なくなる)。ほとんど view から呼ばれるのだが、一部 controller から呼ばれる可能性もあるため、今回は app/controllers/application_controller.rb に記述し、helper_method とする。request.path で現在のパスを取得し、それを title_from_path メソッドに渡す。
# @return [String] 現在のページタイトルを取得する。 def page_title title_from_path(request.path) end helper_method :page_title
title_from_path は path 文字列から locale 用の文字列を取り出すメソッドである。まず、routes の recognize_path により teacher/years という文字列から path のハッシュを取り出す。次にこのハッシュから :controller と :action の文字列を取り出す。この場合の中身はそれぞれ、’teacher/years’ と ‘index’ になる。「/」は locale 文字列に使えないので、gsub で _ に変換することで、最終的にviews.teacher_years.index.title という文字列を得る。これを t メソッドで変換することで、「年度変更」を取得できる。
# @param [String] URL # @return [String] タイトル def title_from_path(path) path = Rails.application.routes.recognize_path(path) c, a = path.values_at(:controller, :action) value = t([ 'views', c.gsub('/', '_'), a, 'title' ].join('.')) end helper_method :title_from_path
上記の修正でページのタイトルが年度変更と表示されるようになった。turnip の feature は「年度一覧」が表示されているかをテストしているので、テストに失敗してしまった。こちらはテストを修正した。
breadcrumb の view の修正
ここまで breadcrumb の表示部は Home へのリンクだけで、後は文字列を表示する処理だけを記述していた。この部分も content_for で対応する。app/views/shared/_top_link_bar.html.haml を以下のように修正する。
= yield :navi if content_for(:navi)
先ほどの app/views/teacher/years/index.html.haml の :title コンテンツの下に :navi コンテンツを追加する。navi メソッドにタイトルとパスを併記した配列を渡す。タイトルを nil にした場合にはパスから自動的に読み取ることとする。当初配列の配列にするつもりだったが、表記を楽にするために 2n 個の要素を持つ配列にした。
- content_for :navi do = navi [ nil, teacher_years_path ]
navi は app/helpers/application_helper.rb に記述する。これは、render するだけの簡単なもの。
# @note ナビゲーションリンクを表示 def navi(array) render(partial: 'shared/navi_link_bar', locals:{ navi: array }) end
app/views/shared/_navi_link_bar.html.haml は以下のようになる。each_slice(2) で配列から二つずつ取り出し、タイトルとパスを取得する。タイトルが nil の場合には title_from_path を使ってタイトル文字列を自動生成する。
%ul.breadcrumb %li= "#{now_year.wareki_nendo}・ユーザ名" %li= link_to lh('Home'), root_path - last = navi.last - navi.each_slice(2) do |(value, path)| %li - if !path || path == last = value || title_from_path(path) -else -if value = link_to value, path -else = link_to *title_with_path(path)
また、パン屑リストの最後は自分自身を示すので、リンクは作成しない。このため、リンクを省略した書き方もできる。例えば、app/views/teacher/kyoumus/index.html.haml では以下のように書いている。
- content_for :navi do = navi [ @title ]
逆に、今後 teacher/year#show などを追加することがあるようであれば、以下のように #index における表記に追記するだけでよくなる。このため、パンくずリストが進むようなことが可能性がある場合は、基本的に前者のような記載をする予定である。
- content_for :navi do = navi [ nil, teacher_years_path, nil, teacher_year_path ]
最後の title_with_path は title_from_path と path を並べたものである。これは view でしか使用しないので、app/helpers/applicaiton_helper.rb に記述する。今後あちこちの view で活躍するメソッドになると期待する。
# @param [String] URL # @return [Array<String>] 翻訳文字列と URL の配列 def title_with_path(path) [ title_from_path(path), path ] end
今日はここまで。
written by iHatenaSync