Bootstrap 3 の導入

背景

これまで作ってきたページは見た目がみすぼらしい感じでした。せっかくなので最近流行りの CSS である Bootstrap 3 を使ってみようと思います。Bootstrap 3 については色々なサイトで紹介されていますが、Bootstrap の使い方というページが分かりやすかったです。このページのサンプルを見ながら、ページを作って行きます。Bootstrap 導入後のページを見てもらった方がわかりやすいと思うので、heroku に deploy した森高千里データベースを参照しながら読んでください。

Bootstrap 3 の導入

通常は Bootstrap のサイトからダウンロードしたものを、app/assets の下に展開するのですが、heroku 自体の容量にも上限があるため、bootstrapcdn から逐次読み込む設定とします。この場合は、レイアウトファイルに cssjavascript の読み込み設定を一行ずつ追加するだけです。

    = stylesheet_link_tag "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css", media:"screen"
    = javascript_include_tag "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"

これだけですでに画面上のフォントが切り替わっていることに気づきます。

ナビゲーションリンクバーの修正

これまでナビゲーションリンクバーはテーブルで描画していました。これをブラウザのタブバーのような描画に変更してみます。タブバーの場合には、該当のタブがアクティブなのかどうかを判断する必要があります。今回は現在動作中のコントローラクラスと比較することで、アクティブかどうかを判断します。そこで、app/helpers/application_helper.rb に css クラスを設定する以下のメソッドを追加します。

  def active_from_class(selected_class)
    controller.class == selected_class ? { class: :active } : {}
  end

この変更により、app/views/shared/_top_link_bar.html.haml は以下のようになります。

%ul.nav.nav-tabs
  %li{active_from_class(TopController)}=link_to t('link.home'), root_path
  %li{active_from_class(TitlesController)}=link_to t('link.titles'), titles_path
  %li
    -if @is_ja
      =link_to :English, recursive_path(locale: :en)
    -else
      =link_to :Japanese, recursive_path(locale: :ja)

table を ul に変更、active チェック

タイトル一覧ページの修正

頭文字のリンク

タイトル一覧ページで悩んだのは頭文字のリンクでした。50 弱のリンクを今のように並べるのはレイアウト的にいけてないので、行ごとにボタンを設定し、その下にドロップダウンメニューを置くことにしてみました。そのため、app/controllers/application_controller.rb で設定した JHeads, EHeads を行ごとにまとめます。また、リンク用ヘッダ LHeads も定数で準備してしまうことにします。

  JHeads = [ %w(あ い う え お), %w(か き く け こ), %w(さ し す せ そ), %w(た ち つ て と), %w(な に ぬ ね の), %w(は ひ ふ へ ほ), %w(ま み む め も), %w(や ゆ よ), %w(ら り る れ ろ), %w(わ を) ]
  EHeads = [ %w(A I U E O), %w(KA KI KU KE KO), %w(SA SHI SU SE SO), %w(TA CHI TSU TE TO), %w(NA NI NU NE NO), %w(HA HI FU HE HO), %w(MA MI MU ME MO), %w(YA YU YO), %w(RA RI RU RE RO), %w(WA WO) ]
  LHeads = %w(00 01 02 03 04 10 11 12 13 14 20 21 22 23 24 30 31 32 33 34 40 41 42 43 44 50 51 52 53 54 60 61 62 63 64 70 72 74 80 81 82 83 84 90 94)

この結果、app/controllers/titles_controller.rb を以下のように修正します。LHeads を準備してしまったので非常に簡潔になってしまいました。また、個別のリンクが見えなくなったので、現在選択中の頭文字(@head_str)をタイトルに表示することにしました。

  def index
    @head = params[:head]
    @head = "00" unless /^\d\d$/ =~ @head
    @titles = Title.head_value_is(@head).order_yomi
    @heads = @is_ja ? JHeads : EHeads
    @lhead_hash = @heads.flatten.zip(LHeads).to_h
    @head_str = @lhead_hash.invert[@head]
    @ids = { head:@head }
  end 

頭文字のリンクは、これらの情報を用いてドロップダウンメニューを付加したボタングループで描画します。また、タイトル行には頭文字を () 付で表示しておきます。

%h1 #{t '.title'} (#{@head_str})

.btn-group
  -@heads.each do |array|
    -first = array.first
    -last = array.last
    .btn-group
      =button_tag class:"btn btn-default dropdown-toggle", "data-toggle" => "dropdown" do
        ="#{first} - #{last}"
      %ul.dropdown-menu
        -array.each do |fl|
          %li=link_to fl, titles_path(head:@lhead_hash[fl]) if fl
データ本体

データ表示部は、枠線あり、行ごとに色づけ、マウスオーバーで強調表示を行います。また Edit と Destroy のリンクもボタングループで描画します。ボタングループクラスですが、中身は button tag ではなく、ただのアンカータグ(link_to)です。

%table.table-bordered.table-striped.table-hover
  %thead
    %tr
      -%w(link.titles).each do |k|
        %th=t k
      -if @is_dev
        %th=t 'head.control'
  %tbody
    -@titles.each do |title|
      -name = title.name(@is_ja)
      %tr{id:name}
        %td=name
        -if @is_dev
          %th
            .btn-group.btn-group-xs
              =link_to t('link.edit'), edit_title_path(title), class:"btn btn-default"
              =link_to t('link.destroy'), title_path(title), class:"btw btn-default", method: :delete, data:{ confirm:t('confirm.destroy') } if title.can_delete?

新規タイトル追加部もボタングループで描画します。btn-group-justified にすることで、横幅いっぱいのボタンになります。

 -if @is_dev
  %hr
  .btn-group.btn-group-justified
    =link_to t('titles.new.title'), new_title_path, class:"btn btn-default"

form 関係の修正

app/views/titles/_form.html.haml も同様に修正します。枠線あり、行ごとに色つけ、submit ボタンの形状を設定します。

=form_for @title do |f|
  =display_error(@title)
  %table.table-bordered.table-striped
    -[ :japanese, :english, :yomi ].each do |key|
      %tr
        %th=f.label key
        %td=f.text_field key
    %tr
      %td.text-center{colspan:2}=f.submit nil, class:"btn btn-default"

また、application_helper の alert_message の display_error のエラー表示部についても css クラスを設定します。

  # model エラー表示
  def display_error(model)
    if model.errors.any?
      error_hash = model.errors.map { |attr, msg| [attr, model.errors.full_message(attr, msg)] }.reverse.to_h
      render inline:<<-HAML, type: :haml, locals:{error_hash:error_hash}
.alert-danger
  %ul
    =list_of error_hash.keys.reverse.each do |key|
      =error_hash[key]
HAML
    end
  end

トップ画面

トップ画面は jumbotron でページタイトルを書いてみました。また、下にはこれから作成するモデルの概要を表示してみました。また、heroku の 10000 行制限も気になるため、各モデルの件数をバッジで表示してみます。app/views/top/index.html.haml は以下のようになりました。

.jumbotron
  %h1=t '.title'
  %p=t '.message'

%h2=t '.summary'
%ul.list-group
  %li.list-group-item
    %span.badge=Title.count
    =t 'link.titles'

feature の修正

今までリンクがわかりにくかったので大括弧を付けていました。ボタンのような見た目となりリンクがはっきりしたので、リンク文字列から大括弧を外したためにエラーとなりました。原因がはっきりしているので、これらのリンク文字列を修正したところ、すべてのテストが通過しました。

まとめ

以上、CSS クラスを設定するだけで見た目がまるっきり変わってしまいました。流行っている理由がよくわかった気がしました。なお、見た目は変わっているものの haml の構成は変更されていないので、feature はほぼ変更ありませんでした。