Rails Tutorialsで勉強のメモ　その5(レイアウトの作成)

# やること

* アプリケーションに`Bootstrap`フレームワークを組み込み、カスタムスタイルを追加
* 作成するページへのリンクをレイアウトに追加
* パーシャルRailsのルーティング、`Asset Pipeline`、`Sass`
* `RSpec`テクニックを用いたリファクタリング

# 構造を追加する

* `Bootstrap`
    * Twitter社のオープンソースのWebデザインフレームワーク
* 画面の変更
    * リンク等のレイアウト変更
    * 各種ページへのリンクを追加
    * サインアップページへのリンクを追加

```bash:レイアウト変更のためのブランチを作成
$ git checkout -b filling-in-layout
```

## ナビゲーションの追加

* リンクとスタイルを追加
    * レイアウトファイルの`application.html.erb`にHTML構造を追加
    * `<div>`タグの追加、CSSクラスの追加、サイトナビゲーションの追加

```html+erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
    <!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
  </head>
  <body>
    <header class="navbar navbar-fixed-top navbar-inverse">
      <div class="navbar-inner">
        <div class="container">
          <%= link_to "sample app", '#', id: "logo" %>
          <nav>
            <ul class="nav pull-right">
              <li><%= link_to "Home",    '#' %></li>
              <li><%= link_to "Help",    '#' %></li>
              <li><%= link_to "Sign in", '#' %></li>
            </ul>
          </nav>
        </div>
      </div>
    </header>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>
```

* `<!--[if lt IE 9]> - <!--[endif]>`
    * IEのバージョンが9未満の場合にのみ、囲まれている部分の行を実行
    * HTMLの機能で、条件付コメントと呼ばれる
* `<header>`タグ
    * ページのトップに来るべき要素
        * 3つのCSSクラスをスペース区切りで与えている
    * `Bootstrap`において特別な意味を持つ
* `<div>`タグ
    * ドキュメントを別々のパーツに分けるのに利用
    * 設定しているclassは`Bootstrap`において特別な意味を持つ
        * `navbar-inner`、`container`
* `<%= link_to "Home", '#' %>`
    * リンクを生成するヘルパー
    * 第1引数：リンクテキスト
    * 第2引数：URL
    * 第3引数(オプション)：オプションハッシュ。HTMLオプションを柔軟に追加できる
* `<nav>`タグ
    * 内部がナビゲーションリンクであることを表す
    * `<ul>`タグの`nav`と`pull-right`クラスは`Bootstrap`において特別な意味を持つ

```html:navタグの埋め込みRuby評価後のソース
<nav>
  <ul class="nav pull-right">
    <li><a href="#">Home</a></li>
    <li><a href="#">Help</a></li>
    <li><a href="#">Sign in</a></li>
  </ul>
</nav>
```

* レイアウト修正後の画面
![5-1-1-1.png](https://qiita-image-store.s3.amazonaws.com/0/38764/5112b4f7-2b7d-a7e0-2426-b7b8e18804ae.png)

* Home画面の修正

```html+erb:app/views/static_pages/home.html.erb
<div class="center hero-unit">
  <h1>Welcome to the Sample App</h1>

  <h2>
    This is the home page for the
    <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", '#', class: "btn btn-large btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails"), 'http://rubyonrails.org/' %>
```

![5-1-1-2.png](https://qiita-image-store.s3.amazonaws.com/0/38764/aadbc799-1626-681d-afb0-0c97605c0d6f.png)

* `hero-unit`、`btn`、`btn-primary`クラス
    * `Bootstrap`において特別な意味を持つ
* `image_tag`ヘルパー
    * `img`タグの生成
    * 第1引数：画像ファイル名
    * 第2引数：ハッシュ

```html:image_tagの埋め込みRuby評価後のソース
<img alt="Rails" src="/assets/rails.png" />
```

## BootstrapとカスタムCSS

* `Bootstrap`を使用するメリット
    * 洗練されたWebデザインとUI要素を簡単にHTML5アプリに追加できる
    * カスタムCSSルールと`Bootstrap`を組合わせて、サンプルアプリにスタイルを追加

* `Bootstrap`の導入
    * `bootstrap-sass gem`を使用してRailsアプリに導入
* `Bootstrap`の言語
    * `LESS CSS`言語
    * Railsの`Asset Pipeline`は`Sass`言語をサポート
    * `bootstrap-sass`で`LESS`を`Sass`に変換する

```rb:Gemfileにbootstrap-sassを追加
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.4'
gem 'bootstrap-sass', '2.3.2.0'
gem 'sprockets', '2.11.0'

(中略)
```

```rb:config/application.rb ※Rails4.0以降の場合のみ必要
require File.expand_path('../boot', __FILE__)
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "sprockets/railtie"
Bundler.require(*Rails.groups)

module SampleApp
  class Application < Rails::Application
    config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
  end
end
```

```bash:Bootstrapの組み込み
# Bootstrapのインストール
$ bundle install

# Webサーバの再起動
# Ctrl+CなどでRailsサーバを停止
$ rails s &
```

* カスタムCSS用のファイル
    * `app/assets/stylesheets/custom.css.scss`を作成
    * `Asset Pipeline`の一部であり、上記ディレクトリに格納されたスタイルシートは`application.css`の一部として自動的にWebサイトのレイアウトにインクルードされる
    * `.css`が含まれているのでCSSファイル
    * `.scss`が含まれているので`Sass`を記述できるCSSファイル（Sassy CSS: Scss）
    * `@import`を使って、`Bootstrap`をインクルードする

```scss:app/assets/stylesheets/custom.css.scss
@import "bootstrap";
```

* この時点での画面表示
![5-1-2-1.png](https://qiita-image-store.s3.amazonaws.com/0/38764/efe8a850-2dc6-dee8-5a46-b6bafb8b9c93.png)

* `custom.css.scss`にスタイルを定義

```css:app/assets/stylesheets/custom.css.scssにスタイルを追加
@import "bootstrap";

html {
  overflow-y: scroll;
}

/* 
 ページ上部に60ピクセルの余白を追加
 headerタグにnavbar-fixed-topクラスが与えられているので、
 これに従いBootstrapはナビゲーションバーをページ上部に固定し、
 ナビゲーションバーの下に余白を置いて主要部分から分離する
 */
body {
  padding-top: 60px;
}

section {
  overflow: auto;
}

textarea {
  resize: vertical;
}

/*
 centerクラスにtext-align: centerプロパティを関連付けている
 centerクラスに属しているタグの内側にある要素は全てセンタリングされる
 */
.center {
  text-align: center;
}

.center h1 {
  margin-bottom: 10px;
}
```

* 画面表示の変更を確認
![5-1-2-2.png](https://qiita-image-store.s3.amazonaws.com/0/38764/a90864ac-9e28-7c0b-6ded-397b944ec9d5.png)

* サイトのテキストの外観を変更
    * 洗練されたタイポグラフィーを利用

```css:app/assets/stylesheets/custom.css.scssにタイポグラフィーの設定を追加
@import "bootstrap";

（中略）

/* typography */

h1, h2, h3, h4, h5, h6 {
  line-height: 1;
}

h1 {
  font-size: 3em;
  letter-spacing: -2px;
  margin-bottom: 30px;
  text-align: center;
}

h2 {
  font-size: 1.2em;
  letter-spacing: -1px;
  margin-bottom: 30px;
  text-align: center;
  font-weight: normal;
  color: #999;
}

p {
  font-size: 1.1em;
  line-height: 1.7em;
}
```

* サイトのテキストを変更した後の画像
![5-1-2-3.png](https://qiita-image-store.s3.amazonaws.com/0/38764/f472c877-8192-ab4f-1c08-1ba78edd9e6c.png)

* サイトロゴのスタイル変更
    * テキストを大文字に変換
    * サイズ、色、配置の変更

```css:app/assets/stylesheets/custom.css.scssにサイトロゴの設定を追加
@import "bootstrap";

(中略)

/* header */

#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  line-height: 1;
}

#logo:hover {
  color: #fff;
  text-decoration: none;
}
```

* サイトロゴ修正後の画像

![5-1-2-4.png](https://qiita-image-store.s3.amazonaws.com/0/38764/6ff52af0-b3db-3d1a-a6e5-c3fc59e4cc68.png)

## パーシャル(partial)

* 現状の問題点
    * `HTML shim`だけで3行使ってしまっている
        * `IE`特有の文法を使用してしまっている
    * HTMLヘッダーは論理的な単位を形成するため、一箇所にまとめる必要がある

* パーシャル機能によって整理する
    * `render`を使い、IE固有の設定およびヘッダー部分の記述を変更

```html+erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
    <%= render 'layouts/shim' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>
```

* `<%= render 'layouts/shim' %>`
    * `app/views/layouts/_shim.html.erb`というファイルを検索してその内容を評価し、結果をビューに挿入
    * パーシャルの命名規則として、ファイル名に`_`をつける

```html+erb:app/views/layouts/_shim.html.erbでパーシャルを作成
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
```

```html+erb:app/views/layouts/_header.html.erbでパーシャルを作成
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="navbar-inner">
    <div class="container">
      <%= link_to "sample app", '#', id: "logo" %>
      <nav>
        <ul class="nav pull-right">
          <li><%= link_to "Home", '#' %></li>
          <li><%= link_to "Help", '#' %></li>
          <li><%= link_to "Sign in", '#' %></li>
        </ul>
      </nav>
    </div>
  </div>
</header>
```

* フッターの作成

```html+erb:app/views/layouts/_footer.html.erbでパーシャルを作成
<footer class="footer">
  <small>
    <a href="http://railstutorial.jp/">Rails Tutorial</a>
    by Michael Hartl
  </small>
  <nav>
    <ul>
      <li><%= link_to "About",   '#' %></li>
      <li><%= link_to "Contact", '#' %></li>
      <li><a href="http://news.railstutorial.jp/">News</a></li>
    </ul>
  </nav>
</footer>
```

```html+erb:app/views/layouts/application.html.erbにフッターのパーシャルを組み込む
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= stylesheet_link_tag    "application", media: "all", "data-turbolinks-track" => true %>
    <%= javascript_include_tag "application", "data-turbolinks-track" => true %>
    <%= csrf_meta_tags %>
    <%= render 'layouts/shim' %>
  </head>
  <body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= render 'layouts/footer' %>
    </div>
  </body>
</html>
```

* フッターを追加した画面を確認

![5-1-3-1.png](https://qiita-image-store.s3.amazonaws.com/0/38764/e7619a0b-32a4-4e79-8bb4-140cae05ee8c.png)

* フッターのスタイルを追加

```css:app/assets/stylesheets/custom.css.scss
@import "bootstrap";

(中略)

/* footer */

footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: #999;
}

footer a {
  color: #555;
}

footer a:hover {
  color: #222;
}

footer small {
  float: left;
}

footer ul {
  float: right;
  list-style: none;
}

footer ul li {
  float: left;
  margin-left: 10px;
}
```

* フッターのスタイル設定後の画面を確認

![5-1-3-2.png](https://qiita-image-store.s3.amazonaws.com/0/38764/7e7adfdd-9bc2-6df2-5392-94e06b04b115.png)

# SassとAsset Pipeline

* `Asset Pipeline`
    * CSS、Javascript、画像などの静的コンテンツの生産性と管理を大幅に強化する機能
* `Sass`
    * CSS生成ツール

### Asset Pipeline

* 主要な機能
    1. アセットディレクトリ
    2. マニフェストファイル
    3. プリプロセッサエンジン

---

* アセットディレクトリ
    * Rails3.0以前のバージョン
        * `public/stylesheets`
        * `public/javascripts`
        * `public/images`
    * Rails3.1以降のバージョン - 目的別に静的ファイルを分類。それぞれに`stylesheets`、`javascripts`、`images`ディレクトリが存在する
        * `app/assets`：現在のアプリケーション固有のアセット
        * `lib/assets`：自身の開発チームによって作成されたライブラリ用のアセット
        * `vendor/assets`：サードパーティーのアセット

---

* マニフェストファイル
    * アセットディレクトリのファイルをどのように1つのファイルにまとめるかをRailsに指示
    * 実際にまとめるのは`Sprockets gem`
    * CSSとJavaScriptには適用されるが、画像ファイルには適用されない

* `*= require_tree .`
    * `app/assets/stylesheets`ディレクトリの全てのCSSをアプリケーションCSSにインクルードすることを指す
* `*= require_self`
    * CSSの読み込みの際に、`application.css`自身もインクルードする
* 今回は特に変更しない


```css+erb:マニフェストファイルapp/assets/stylesheets/application.css
/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the top of the
 * compiled file, but it's generally better to create a new file per style scope.
 *
 *= require_self
 *= require_tree .
 */
```

* プリプロセッサエンジン
    * 必要なアセットをディレクトリに配置してまとめた後、Railsは様々なプリプロセッサエンジンを介してそれらを実行
    * ブラウザに配信できるようにマニフェストファイルを用いて結合し、際とテンプレート用に準備する
* Railsでどのプリプロセッサを使用するかの判定
    * ファイルの拡張子で判断
        * `.scss`：Sass
        * `.coffee`：CoffeeScript
        * `.erb`：埋め込みRuby（ERb）
    * 繋げて実行することができる
        * `foobar.js.coffee`：CoffeeScriptプロセッサ経由で実行される
        * `foobar.js.erb.coffee`：CoffeeScriptとERbの両方で実行される
            * 右から左に実行されるので、CoffeeScript => ERbの順に実行される

---

* `Asset Pipeline`のメリット
    * 本番のアプリケーションで効率的になるように最適化されたアセットも自動的に生成される
* 従来のCSSとJavaScriptを整理する手法
    * 機能を個別のファイルに分割し、読みやすいフォーマットに整形
    * プログラマにとっては可読性があるが、圧縮されていないので本番環境では非効率
* `Asset Pipeline`
    * 全てのスタイルシートを1つのCSSファイル（`application.css`）にまとめる
    * 全てのJavaScriptファイルを1つのJSファイル（`javascripts.js`）にまとめる
    * それらのファイル全てに対して不要な空白を取り除く
    * ファイルサイズを最小化する
* プログラマにとっては見やすく分割されたフォーマットのファイルを提供
* 本番環境に対しては最適化された1つのファイルを提供

## Sass

* `Sass`とは
    * スタイルシートを記述するための言語
    * CSSよりも多くの点で強化されている
    * 本節ではネストと変数について説明
        * ミックスインについては第7章で説明
    * SCSSフォーマットに対応
        * CSS本体を抽象化したフォーマット
        * CSSに新しい機能を追加しただけで、新しい構文を定義したものではない
    * 拡張子は`.scss`

### ネスト

* ネスト
    * スタイルシート内に共通のパターンがある場合、要素をネストすることができる

```css:通常のCSSの表記：.centerへのルール
.center {
  text-align: center;
}
.center h1 {
  margin-bottom: 10px;
}
```

```scss:Sassでの表記：.centerをネストして記載
.center {
  text-align: center;
  h1 {
    margin-bottom: 10px;
  }
}
```

```css:通常のCSSでの表記：#logoというidが重複
// #logoの定義
#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  line-height: 1;
}

#logo:hover {
  color: #fff;
  text-decoration: none;
}
```

```scss:Sassでの表記：親属性を参照するのに&を使用
#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  line-height: 1;
  &:hover {
    color: #fff;
    text-decoration: none;
  }
}
```

```css:フッターのCSS
footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: #999;
}

footer a {
  color: #555;
}

footer a:hover {
  color: #222;
}

footer small {
  float: left;
}

footer ul {
  float: right;
  list-style: none;
}

footer ul li {
  float: left;
  margin-left: 10px;
}
```

```scss:フッターのCSSをSCSSで記載
footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: #999;
  a {
    color: #555;
    &:hover {
      color: #222;
    }
  }
  small {
    float: left;
  }
  ul {
    float: right;
    list-style: none;
    li {
      float: left;
      margin-left: 10px;
    }
  }
}
```

### 変数

* 変数
    * 同じ値を変数として定義・参照することで、冗長なコードを削除し、より自由な表現を可能とする
    * 繰り返し使わないとしても、可読性がよくなるので定義すべき
    * `Bootstrap`フレームワークにおいても多くの色などに対して変数名を定義している
        * [LESS変数一覧](http://bootstrapdocs.com/v2.0.4/docs/less.html)を参照
        * `bootstrap-sass`というgemを使用することで、Sassでも同様の変数が使える

```css:通常のCSS：#999を複数個所で使用
h2 {
  color: #999;
}
footer {
  color: #999;
}
```

```scss:SCSS：#999を変数として定義
$lightGray: #999;
h2 {
  color: $lightGray;
}
footer {
  color: $lightGray;
}
```

```scss:SCSS：Bootstrapフレームワークで定義している変数を利用
h2 {
  color: $grayLight;
}
footer {
  color: $grayLight;
}
```

* ネスト・変数を使用して、SCSSファイルを書き換える

```scss:app/assets/stylesheets/custom.css.scss
@import "bootstrap";

/* mixins, variables, etc. */
$grayMediumLight: #eaeaea;

/* universal */

html {
  overflow-y: scroll;
}

body {
  padding-top: 60px;
}

section {
  overflow: auto;
}

textarea {
  resize: vertical;
}

.center {
  text-align: center;
  h1 {
    margin-bottom: 10px;
  }
}

/* typography */

h1, h2, h3, h4, h5, h6 {
  line-height: 1;
}

h1 {
  font-size: 3em;
  letter-spacing: -2px;
  margin-bottom: 30px;
  text-align: center;
}

h2 {
  font-size: 1.2em;
  letter-spacing: -1px;
  margin-bottom: 30px;
  text-align: center;
  font-weight: normal;
  color: $grayLight;
}

p {
  font-size: 1.1em;
  line-height: 1.7em;
}

/* header */

#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: $white;
  text-transform: uppercase;
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  line-height: 1;
  &:hover {
    color: $white;
    text-decoration: none;
  }
}

/* footer */

footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: $grayLight;
  a {
    color: $gray;
  }
  &:hover {
    color: $grayDarker;
  }
  small {
    float: left;
  }
  ul {
    float: right;
    list-style: none;
    li {
      float: left;
      margin-left: 10px;
    }
  }
}
```

# レイアウトのリンク

* レイアウトのリンク
    * 現時点では全て#
    * `<a href="/static_pages/about">About</a>`はいけてない
        * Railsでは`/about`となるようにすべき
    * Railsの場合、`<%= link_to "About", about_path %>`などとする
        * 可読性が増す
        * `about_path`に定義しておくことで、URLを変更したい場合にも容易に変更できる

* サンプルアプリケーションの全てのリンクリスト

| ページ | URL | 名前付きルート |
| ----- | --- | ------------- |
| Home | / | root_path |
| About | /about | about_path |
| Help | /help | help_path |
| Contact | /contact | contact_path |
| Sign up | /signup | signup_path |
| Sign in | /signin | signin_path |

* Contactは既に第3章で作成済み

### 名前付きルートのテスト

* テストコードの修正
    * `visit '/static_pages/about'`となっているような部分を`visit about_path`に置き換える
* テストを実行するとエラーになる
    * `bundle exec rspec spec/requests/static_pages_spec.rb`

```rb:spec/requests/static_pages_spec.rb：アドレスを名前付きルートに変更
require 'spec_helper'

describe "StaticPages" do

  let(:base_title) { "Ruby on Rails Tutorial Sample App" }

  describe "Home page" do
    it "should have the content 'Sample App'" do
      visit root_path
      expect(page).to have_content('Sample App')
    end

    it "should have the title 'Home'" do
      visit root_path
      expect(page).to have_title("#{base_title} - Home")
    end
  end

  describe "Help page" do
    it "should have the content 'Help'" do
      visit help_path
      expect(page).to have_content('Help')
    end

    it "should have the title 'Help'" do
      visit help_path
      expect(page).to have_title("#{base_title} - Help")
    end
  end

  describe "About page" do
    it "should have the content 'About Us'" do
      visit about_path
      expect(page).to have_content('About Us')
    end

    it "should have the title 'About'" do
      visit about_path
      expect(page).to have_title("#{base_title} - About Us")
    end
  end

  describe "Contact page" do
    it "should have the content 'Contact'" do
      visit contact_path
      expect(page).to have_content('Contact')
    end

    it "should have the title 'Contact'" do
      visit contact_path
      expect(page).to have_title("#{base_title} - Contact")
    end
  end
end
```

## Railsのルート

* RailsがURLマッピングに使用するファイル
    * `config/routes.rb`
* 現在のURLマッピングの設定
    * `get 'static_pages/help'`
* 名前付きルートに変更した場合
    * `match '/help', to: 'static_pages#help', via: 'get'`
        * `/help`へのGETリクエストにマッチ
        * `StaticPages`コントローラの`help`アクションにルーティングされる
    * `match '/help'`というコードにより、下記の名前付きルートが自動生成される
        * `about_path -> '/about'`
        * `about_url -> 'http://localhost:3000/about'`

```rb:config/routes.rb：名前付きルートの定義
SampleApp::Application.routes.draw do
  match '/help', to: 'static_pages#help', via: 'get'
  match '/about', to: 'static_pages#about', via: 'get'
  match '/contact', to: 'static_pages#contact', via: 'get'
end
```

* 上記変更後にテストを再実行
    * `home`以外はOKになる
* `home`を`config/routes.rb`に記載するには
    * `root 'static_pages#home'`と書く
    * `match '/', to: 'static_pages#home', via: 'get'`でも書けるが、上記が推奨
    * `root 'static_pages#home'`というコードにより、下記の名前付きルートが自動生成される
        * `root_path -> '/'`
        * `root_url -> 'http://localhost:3000/'`
* `root`の設定を追加後にテストを実行すると全てOKになる

```rb:config/routes.rb：homeの設定を追加
SampleApp::Application.routes.draw do
  root 'static_pages#home'
  match '/help', to: 'static_pages#help', via: 'get'
  match '/about', to: 'static_pages#about', via: 'get'
  match '/contact', to: 'static_pages#contact', via: 'get'
end
```

### 名前付きルート

* `link_to`メソッドの変更
    * ヘッダーのパーシャルとフッターのパーシャルを修正
    * 当変更後、`Home`、`Help`、`About`、`Contact`へのリンクが有効になる

```html+erb:app/views/layouts/_header.html.erb
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="navbar-inner">
    <div class="container">
      <%= link_to "sample app", root_path, id: "logo" %>
      <nav>
        <ul class="nav pull-right">
          <li><%= link_to "Home", root_path %></li>
          <li><%= link_to "Help", help_path %></li>
          <li><%= link_to "Sign in", '#' %></li>
        </ul>
      </nav>
    </div>
  </div>
</header>
```

```app/views/layouts/_footer.html.erb
<footer class="footer">
  <small>
    <a href="http://railstutorial.jp/">Rails Tutorial</a>
    by Michael Hartl
  </small>
  <nav>
    <ul>
      <li><%= link_to "About",   about_path %></li>
      <li><%= link_to "Contact", contact_path %></li>
      <li><a href="http://news.railstutorial.jp/">News</a></li>
    </ul>
  </nav>
</footer>
```

## RSpecを洗練させる

* RSpecのテスト内容が冗長で繰り返しが多くなってきている

```rb:spec/requests/static_pages_spec.rbの抜粋
  describe "Home page" do
    it "should have the content 'Sample App'" do
      visit root_path
      expect(page).to have_content('Sample App')
    end

    it "should have the title 'Home'" do
      visit root_path
      expect(page).to have_title("#{base_title} - Home")
    end
  end
```

* `visit`が重複している
    * `before`ブロックを使用して冗長箇所を除去する

```rb:spec/requests/static_pages_spec.rb：beforeブロックに変更
  describe "Home page" do
    before { visit root_path }
    it "should have the content 'Sample App'" do
      expect(page).to have_content('Sample App')
    end

    it "should have the title 'Home'" do
      expect(page).to have_title("#{base_title} - Home")
    end
  end
```

* どっちのテストも`page`変数を使用する
    * `subject`ブロックを使用し、テストの主題が`page`であることを定義する
* `it "should have the content 'Sample App!'" do`と`expect(page).to have_content('Sample App')`は同じことを言っている
    * `it`メソッドの別のものを使用

```rb:spec/requests/static_pages_spec.rb：subjectブロックの使用とitメソッドの変更
  subject { page }
  describe "Home page" do
    before { visit root_path }

    it { should have_content('Sample App') }
    it { should have_title("#{base_title} - Home") }
  end
```

* `let`ブロックで`base_title`を定義しているが、ユーティリティクラスに持たせたい
    * `spec/support`ディレクトリに`utilities.rb`ファイルを作成し、`full_title`メソッドを定義
    * `spec/support`ディレクトリはRSpecによって自動的に読み込まれる

```rb:spec/support/utilities.rb
def full_title(page_title)
  base_title = "Ruby on Rails Tutorial Sample App"
  if page_title.empty?
    base_title
  else
    "#{base_title} - #{page_title}"
  end
end
```

```rb:spec/requests/static_pages_spec.rb：ユーティリティクラスを参照
  subject { page }
  describe "Home page" do
    before { visit root_path }

    it { should have_content('Sample App') }
    it { should have_title(full_title('Home')) }
  end
```

* 上記を踏まえて、テストクラスをリファクタリング
    * 修正後にテストを実行して、正常終了することを確認

```rb:spec/requests/static_pages_spec.rb：リファクタリング
require 'spec_helper'

describe "StaticPages" do
  subject { page }

  describe "Home page" do
    before { visit root_path }

    it { should have_content('Sample App') }
    it { should have_title(full_title('Home')) }
  end

  describe "Help page" do
    before { visit help_path }

    it { should have_content('Help') }
    it { should have_title(full_title('Help')) }
  end

  describe "About page" do
    before { visit about_path }

    it { should have_content('About Us') }
    it { should have_title(full_title('About Us')) }
  end

  describe "Contact page" do
    before { visit contact_path }

    it { should have_content('Contact') }
    it { should have_title(full_title('Contact')) }
  end
end
```

# ユーザー登録

* ユーザー登録ページへのルーティングを作成
    * 2番目のコントローラを作成する必要がある

## Usersコントローラ

```bash:Usersコントローラの生成（newアクションを追加）
$ rails generate controller Users new --no-test-framework
      create  app/controllers/users_controller.rb
       route  get "users/new"
      invoke  erb
      create    app/views/users
      create    app/views/users/new.html.erb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.js.coffee
      invoke    scss
      create      app/assets/stylesheets/users.css.scss
```

## ユーザー登録用URL

* テスト用ファイルの作成

```bash:テスト用ファイルの作成
$ rails generate integration_test user_pages
      invoke  rspec
      create    spec/requests/user_pages_spec.rb
```

```rb:spec/requests/user_pages_spec.rb
require 'spec_helper'

describe "User pages" do
  subject { page }

  describe "signup page" do
    before { visit signup_path }

    it { should have_content('Sign up') }
    it { should have_title(full_title('Sign up')) }
  end
end
```

* `StaticPages`も含めてテストを実施
    * `bundle exec rspec spec/`
    * `user_pages_spec.rb`部分がエラーになる

* ルーティングの設定
    * `/signup`のルートを追加

```rb:config/routes.rb
SampleApp::Application.routes.draw do
  get "users/new"
  root 'static_pages#home'
  match '/signup',  to: 'users#new',            via: 'get'
  match '/help',    to: 'static_pages#help',    via: 'get'
  match '/about',   to: 'static_pages#about',   via: 'get'
  match '/contact', to: 'static_pages#contact', via: 'get'
end
```

* ユーザ登録ページのスタブを作成
    * テストを実施し、正常終了することを確認

```html+erb:app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>Find me in app/views/users/new.html.erb</p>
```

* `home`のページからの`Sign up`へのリンクを修正

```html+erb:app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<div class="center hero-unit">
  <h1>Welcome to the Sample App</h1>

  <h2>
    This is the home page for the
    <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
    sample application.
  </h2>

  <%= link_to "Sign up now!", signup_path, class: "btn btn-large btn-primary" %>
</div>

<%= link_to image_tag("rails.png", alt: "Rails"), 'http://rubyonrails.org/' %>
```

# コミット

```bash:コミット、デプロイ
$ git add .
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout

$ git push
$ git push heroku

$ heroku open

# エラーが発生する場合はログを確認
$ heroku logs
```

# 演習問題

## Shared Examples

* Shared Examples
    * 同じようなテストを複数箇所で実施する場合に使用
    * テンプレートのテストケースを記載し、変数部分だけを各メソッドで`let`にて設定することで、同じようなテストケースの記載を省くことができる

```rb:spec/requests/static_pages_spec.rbの修正前
describe "StaticPages" do
  subject { page }

  describe "Home page" do
    before { visit root_path }

    it { should have_content('Sample App') }
    it { should have_title(full_title('Home')) }
  end
end
```

* Shared Examples適用後
    * Helpなど、他のページにも同様に適用

```rb:spec/requests/static_pages_spec.rbの修正後
describe "StaticPages" do
  subject { page }

  shared_examples_for "all static pages" do
    it { should have_content(heading) }
    it { should have_title(full_title(page_title)) }
  end

  describe "Home page" do
    before { visit root_path }
    let(:heading)    { 'Sample App' }
    let(:page_title) { '' }

    it_should_behave_like "all static pages"
  end
end
```

## click_linkによるレイアウトのリンクのテスト

* `click_link`
    * リンクが実際に正しいページへのリンクになっているかをテスト

```rb:spec/requests/static_pages_spec.rbにリンクのテストを追加
describe "StaticPages" do
  it "should have the right links on the layout" do
    visit root_path

    click_link "About"
    expect(page).to have_title(full_title('About Us'))

    click_link "Help"
    expect(page).to have_title(full_title('Help'))

    click_link "Contact"
    expect(page).to have_title(full_title('Contact'))

    click_link "Home"
    expect(page).to have_title(full_title(''))

    click_link "Sign up now!"
    expect(page).to have_title(full_title(''))

    click_link "sample app"
    expect(page).to have_title(full_title(''))
  end

end
```

## ヘルパーメソッドのテストを作成

```rb:spec/helpers/application_helper_spec.rb
require 'spec_helper'

describe ApplicationHelper do
  it "should include the page title" do
    expect(full_title("foo")).to match(/foo/)
  end

  it "should include the base title" do
    expect(full_title("")).to match(/^Ruby on Rails Tutorial Sample App/)
  end

  it "should not include a bar for the home page" do
    expect(full_title("")).not_to match(/-/)
  end
end
```

```rb:spec/support/utilities.rbの中身を変更(ApplicationHelperをincludeするだけに変更)
include ApplicationHelper
```