Railsチュートリアル 第5章 - レイアウトを作成する…構造を追加する

# このパートでは何をするか

* レイアウトにいくつかの構造を与える
* レイアウトにいくつかのCSSを与える
    * カスタムCSSルール
    * Bootstrap（Twitter社提供のWebデザインフレームワーク）の利用
* コードそのものにスタイルを与える

# 構造を追加したWebサイトのレイアウト

## ナビゲーション

まず、サイトのレイアウトファイルである`application.html.erb`にHTML構造を追加し、レイアウトファイルを更新します。ここでは、以下の要素を追加しています。

* 領域（divタグ）
* CSSクラス
* サイトナビゲーションの起点となる領域

```erb:app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= csrf_meta_tags %>
    <%= stylesheet_link_tag    'application', media: 'all',
                               'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',
                               'data-turbolinks-track': 'reload' %>
    <!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
      </script>
    <![endif]-->
  </head>
  <body>
    <header class="navbar navbar-fixed-top navbar-inverse">
      <div class="container">
        <%= link_to "sample app", '#', id: "logo" %>
        <nav>
          <ul class="nav navbar-nav navbar-right">
            <li><%= link_to "Home",   '#' %></li>
            <li><%= link_to "Help",   '#' %></li>
            <li><%= link_to "Log in", '#' %></li>
          </ul>
        </nav>
      </div>
    </header>
    <div class="container">
      <%= yield %>
    </div>
  </body>
</html>
```

### ブラウザによるHTML解釈の違いの吸収

```erb:
<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
  </script>
<![endif]-->
```

古いバージョンのMicrosoft Internet Explorer[^古いバージョンのMSIE]では、HTML5で書かれたWebサイトを表示すると、レイアウトが大きく崩れます。上述の構文は、そのような事態を回避するための構文です。

この構文は、IE9までのMSIEに搭載されていた「条件付きコメント」機能を用いて、「バージョン9未満のMSIEでのみ、HTML shimを読み込む」という処理を実現しています。「バージョン9以降のMSIE・Firefox・Safari・Chrome等の他ブラウザの動作に影響を与えることなく、古いMSIEに由来するレイアウト崩れを回避する」という好都合な構文です。

[^古いバージョンのMSIE]: もっとも、2019年9月時点では、HTML5 shimが必要になるようなバージョンのMSIEは既にサポート終了となっているので、「サポートが切れたプログラムを使っている人が悪い」と割り切ってしまう手もあります。

### ページヘッダー

```erb:
<header class="navbar navbar-fixed-top navbar-inverse">
  <div class="container">
    <%= link_to "sample app", '#', id: "logo" %>
    <nav>
      <ul class="nav navbar-nav navbar-right">
        <li><%= link_to "Home",   '#' %></li>
        <li><%= link_to "Help",   '#' %></li>
        <li><%= link_to "Log in", '#' %></li>
      </ul>
    </nav>
  </div>
</header>
```

HTML5の`header`要素は、ページの導入的なコンテンツを表す要素です。具体的には、導入部やサイトナビゲーション等が含まれます。通常はページの上部に来るようにレンダリングされます。

この`header`要素には、`navbar`、`navbar-fixed-top`、`navber-inverse`という3つのCSSクラスが適用されています[^HTML属性値列挙の区切り文字]。これらのクラス名は、これから導入するBootstrapフレームワークで特別な意味を持ちます。

なお、HTML5においては、領域を表す要素として、`header`の他に、`nav`、`section`、`footer`などといった要素が定義されています。

[^HTML属性値列挙の区切り文字]: HTMLにおいて、ある属性に対する値を列挙で与える場合、その区切り文字はスペースとなります。

### `div`要素

```erb:
<div class="container">
  ...略
</div>
```

HTMLの`div`要素は、特に文書構造上の意味のない一般的なブロックを表す要素です。`class`属性の`container`という値は、`header`要素に出てきた3つのクラス同様、Bootstrapフレームワークで特別な意味を持ちます。

#### 埋め込みRubyコードを用いたナビゲーションリンクの生成

```erb:
<%= link_to "sample app", '#', id: "logo" %>
<nav>
  <ul class="nav navbar-nav navbar-right">
    <li><%= link_to "Home",   '#' %></li>
    <li><%= link_to "Help",   '#' %></li>
    <li><%= link_to "Log in", '#' %></li>
  </ul>
</nav>
```

リンクを生成するために、Railsヘルパーの`link_to`を用いています。`link_to`ヘルパーの第1引数はリンクテキスト、第2引数はURLです。第2引数には、ひとまずスタブ用の`'#'`を挿入[^link_toの第2引数にひとまずスタブを挿入]しておきます。ここまでが、`link_to`ヘルパーに必須の引数です。

第3引数は、オプションハッシュと呼ばれる可変長のハッシュです。今回は、`sample app`へのリンクに`logo`というIDを付与するために用いられています。オプションハッシュという手法は、Railsでは常套手段として用いられており、これにより、「RailsのコードそのままにHTMLの様々なオプションを付与する」という実装が実現する得ています。オプションハッシュは必須ではなく、実際他の3つの`link_to`ヘルパーにオプションハッシュは与えられていません。

[^link_toの第2引数にひとまずスタブを挿入]: 今後の学習過程で名前付きルートに置き換えます。

#### ナビゲーションリンクのリスト

```erb:
<nav>
  <ul class="nav navbar-nav navbar-right">
    <li><%= link_to "Home",   '#' %></li>
    <li><%= link_to "Help",   '#' %></li>
    <li><%= link_to "Log in", '#' %></li>
  </ul>
</nav>
```

リストアイテムを表す要素である`li`と順不同リストを表す要素`ul`によって構成された、ナビゲーションリンクのリストです。

`nav`要素は、「その内側がナビゲーションリンクである」ということを明確にするための要素です。`class`属性の`nav`・`navbar-nav`・`navbar-right`という値は、`header`要素に出てきた3つのクラス同様、Bootstrapフレームワークで特別な意味を持ちます。

Railsが埋め込みRubyを評価し、レイアウトを描画すると、上記コードは以下のように変化します。

```erb:
<nav>
  <ul class="nav navbar-nav navbar-right">
    <li><a href="#">Home</a></li>
    <li><a href="#">Help</a></li>
    <li><a href="#">Log in</a></li>
  </ul>
</nav>
```

上述のコードが、最終的にWebブラウザに返されるHTMLコードとなります。

#### メインコンテンツ用の`div`

```erb:
<div class="container">
  <%= yield %>
</div>
```

レイアウトの最後の部分、メインコンテンツ用の`div`です。`class`属性の`container`という値は、ここまで見てきた様々なクラスと同様、Bootstrapフレームワークで特別な意味を持ちます。Railsの`yield`メソッドは、Webサイトのレイアウトにページごとの内容を挿入するメソッドです。

### サインアップページへのリンクがあるHomeページ

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

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

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

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

`div`要素の`class`属性にある`jumbotron`という値は、ここまで見てきた様々なクラスと同様、Bootstrapフレームワークで特別な意味を持ちます。

`"Sign up now!"`と書かれた`link_to`は、サイトへのユーザー追加機能を実装するときに使うリンクです。現時点では、仮に`'#'`へのリンクとして記述しています。`class`属性の`btn`・`btn-lg`・`btn-primaly`という値は、ここまで見てきた様々なクラスと同様、Bootstrapフレームワークで特別な意味を持ちます。Railsにより埋め込みRubyが評価され、最終的には、以下のHTMLが生成されることになります。

```erb:
<a href="#" class="btn btn-lg btn-primary">Sign up now!</a>
```

`image_tag`と書かれた`link_to`は、Railsの`image_tag`ヘルパーです。引数としては、画像ファイルのパスとオプションハッシュを取ります。`alt`などの属性は、属性名のシンボルをキー・属性値を値としたハッシュとして与えることにより定義することができます。

`image_tag`ヘルパーにおける画像の参照先パスは、以下の通りとなります。

* `/`始まりでないパスで指定した場合、`app/assets/images`を起点としたパス
* `/`始まりのパスを指定した場合、`public`を起点としたパス

`app/assets/images`というのは、Railsのアセットパイプライン機能に関するディレクトリの一つで、「アプリケーション固有のアセットのうち、画像リソース」という意味です。アセットパイプラインについては、[Railsチュートリアル第5章 - レイアウトを作成する…Sassとアセットパイプライン](#)にて詳しく触れています。

#### `curl`による画像のダウンロード

Unix系のOSにおいては、`curl`というコマンドにより、Web上のリソースを容易にダウンロードすることができます。

```zsh:
>>> pwd
/~/docker/rails_tutorial_test/sample_app
>>> curl -o app/assets/images/rails.png -OL railstutorial.jp/rails.png
```

#### カスタムCSSを使っていないHomeページ

<img width="942" alt="スクリーンショット 2019-09-18 21.44.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/c56d08d3-2502-cd49-d989-952ae847332b.png">

HTML部分のみの作り込みが終わった時点では、ブラウザでHomeページを表示した結果は以上のようになります。


#### `image_tag`の結果

私の環境では、`image_tag`がRailsに解釈された結果は以下の通りとなりました。

```html:
<img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png">
```

以下の事柄は重要です。

* ファイル名が重ならないようにするために、Railsが画像リソースにランダムな文字列を割り当てている
  * 今回は`c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6`であった
  * 例えば画像ファイルを新たなファイルに更新した際、ブラウザ内に保存されたキャッシュと意図的にヒットさせないようにするための仕組みである
* `src`属性に`images`というディレクトリ名は含まれていない
  * Railsが、`assets`ディレクトリ直下の画像を、`app/assets/images`ディレクトリにある画像と紐付けしている
  * ブラウザから見ると、images・javascripts・stylesheetsなど`assets`ディレクトリ以下のすべてのファイルが同じディレクトリにあるように見える
  * これは高速化のための措置
      * フラットなディレクトリ構造をとると、ファイルをより高速にブラウザに渡すことができる
* `alt`属性は、画像がない場合に代わりに表示される文字列
  * 視覚障害がある人向けのスクリーンリーダーなどで用いられる

## 演習 - レイアウトを作成する…ナビゲーション

### 1. Webページと言ったらネコ画像、というぐらいにはWebにはネコ画像が溢れていますよね。[リスト 5.4](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#code-downloading_a_cat_pic)のコマンドを使って、[図 5.3](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#fig-kitten)のネコ画像をダウンロードしてきましょう。

>```bash:リスト5.4のコード
> $ curl -OL cdn.learnenough.com/kitten.jpg
>```


以下、開発環境があるDockerコンテナ内における作業内容です。

```
# pwd
/var/www/sample_app

# curl -OL cdn.learnenough.com/kitten.jpg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  138k  100  138k    0     0  30703      0  0:00:04  0:00:04 --:--:-- 37780
# ls kitten.jpg
kitten.jpg
```

### 2. `mv`コマンドを使って、ダウンロードした`kitten.jpg`ファイルを適切なアセットディレクトリに移動してください。

```
# pwd
/var/www/sample_app
# ls kitten.jpg
kitten.jpg

# ls app/assets/images
rails.png
# mv ./kitten.jpg app/assets/images
# ls app/assets/images
kitten.jpg  rails.png
```

### 3. `image_tag`を使って、`kitten.jpg`画像を表示してみてください。

`app/views/static_pages/home.html.erb`は、以下のように変更します。

```erb:app/views/static_pages/home.html.erb
...略
<%= link_to image_tag("rails.png", alt: "Rails logo"),
            'http://rubyonrails.org/' %>
<%= image_tag "kitten.jpg", alt: "kitten" %>
```

改めて、WebブラウザでHomeページを表示してみましょう。

<img width="942" alt="スクリーンショット 2019-09-19 7.50.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/90bf9101-14d6-9226-1969-3075e354ed15.png">

ネコ画像がちゃんと鎮座しています。

生成されたHTMLにおけるネコ画像の部分は、以下のようなコードになっています。`assets`直下に、ランダムな英数字が羅列された名前のファイルが作られていますね。

```html:
<img alt="kitten" src="/assets/kitten-44dde42a7808d66c6f314c6587e2c0faabb03d8a3c2c47e4d07e09c08e3c1c6b.jpg">
```

## BootstrapとカスタムCSS

### Bootstrapのインストール

今まではHTMLと向き合っていましたが、ここで話は突然`Gemfile`に飛びます。そうです、いよいよBootstrapのインストールです。

まずは`Gemfile`を以下のように書き換えます。

```ruby:Gemfile
source 'https://rubygems.org'

gem 'rails',        '5.1.6'
gem 'bootstrap-sass', '3.3.7'
#...略
```

次いで、開発環境のDockerコンテナで`bundle install`を実行します。Rails環境にGemを追加する際のいつものプロセスですね。

```
# pwd
/var/www/sample_app

# bundle install
Fetching gem metadata from https://rubygems.org/............
...略
Fetching bootstrap-sass 3.3.7
Installing bootstrap-sass 3.3.7
...略
Bundle complete! 22 Gemfile dependencies, 80 gems now installed.
Gems in the group production were not installed.
Bundled gems are installed into `/usr/local/bundle`
```

`bootstrap-sass 3.3.7`が正常にインストールできたようです。

### カスタムCSSの作成

Railsチュートリアルと同様、`touch`コマンドでCSSファイルを新規作成する手法を取ることにします。

```
# pwd
/var/www/sample_app

# touch app/assets/stylesheets/custom.scss

# ls app/assets/stylesheets
application.css  custom.scss  static_pages.scss
```

先ほど登場した`/app/assets/images`同様、`/app/assets/stylesheets`もアセットパイプラインの一部です。`/app/assets/stylesheets`に置かれたスタイルシートは、最終的に`application.css`の一部としてWebサイトのレイアウトに読み込まれます。

`ls`の結果に、拡張子が`.scss`であるファイルがいくつか見受けられます。`.scss`というのは、「Sass(Sassy CSS)」というCSSを拡張した言語で記述されたファイルに対応する拡張子です。Railsにおいて、`/app/assets/stylesheets`に置かれた`.scss`という拡張子を持つスタイルシートは、アセットパイプラインによってSassとして処理されます。

では早速、`app/assets/stylesheets/custom.scss`にBootstrapを読み込んでみましょう。なお同時に、Bootstrapと関連するモジュールであるSprocketsも読み込んでいます。

```sass:app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";
```

<img width="1291" alt="スクリーンショット 2019-09-20 8.01.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/95f47e9b-68a3-7348-51ed-56fec55ee0f0.png">

さらにスタイルを追加していきます。

```sass:app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";

/* universal */

body {
  padding-top: 60px;
}

section {
  overflow: auto;
}

textarea {
  resize: vertical;
}

.center {
  text-align: center;
}

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

<img width="1163" alt="スクリーンショット 2019-09-22 1.38.49.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/6348c202-2acc-99f4-189e-bd947b695245.png">

さらに大きく見た目が変わりました。全体に真ん中に寄り、題名上のパディングがきちんと確保されました。圧迫感のない、ゆとりある見た目です。

今度はタイポグラフィーに関するスタイルを適用してみます。

```sass:app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";

/* universal */
/* ...略 */

/* 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: #777;
}

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

<img width="1163" alt="スクリーンショット 2019-09-22 1.41.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/ed86fd26-f4f9-6b3d-9a91-1d6799a3f596.png">

* 字間がぎゅっと詰まった
* 本文の文字が小さく、字の太さが細くなった

以上のような変化がありました。全体に見た目が引き締まりましたね。

```sass:app/assets/stylesheets/custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";

/* universal */
/* ...略 */

/* typography */
/* ...略 */

/* 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;
}

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

<img width="1163" alt="スクリーンショット 2019-09-22 1.48.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/9627e66b-b02f-84c9-d3b0-d9e29ebaa0f2.png">

それまでヘッダー左側にあった、何やら取ってつけたような「sample app」という文字がなくなりました。その代わり、ヘッダー左側には、きちんと配置やタイポグラフィーに配慮された「SAMPLE APP」という白い文字が流し込まれています。

* HTMLにおける色指定
    * 赤・緑・青の度合いを各256段階に分けて表す
    * 16進数2オクテットの数字3つ（`00`〜`ff`×3）、合わせて6文字で表すのが一般的
        * 順番は赤→緑→青
        * 当該表記の色コードは、頭に`#`という文字が来る
    * 16進数2オクテットの数字3つによる表記は、3文字の省略表記も可能
        * 例えば`#ffffff`を`#fff`と表記するなど
    * 一部の色については、英単語で表記することもできる
        * 例えば`#ffffff`を`white`と表記するなど

## 演習 - BootstrapとカスタムCSS

### 1.1. リスト 5.10を参考にして、5.1.1.1で使ったネコ画像をコメントアウトしてみてください。

```erb:home.html.erb（抜粋）
<%= image_tag "kitten.jpg", alt: "kitten" %>
```

ネコ画像に対応するerbのコードは上述の通りでしたね。

<img width="1163" alt="スクリーンショット 2019-09-24 7.43.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/43a32296-bfba-a998-dae6-49418df81c88.png">

```diff:home.html.erb（抜粋）
- <%= image_tag "kitten.jpg", alt: "kitten" %>
+ <%#= image_tag "kitten.jpg", alt: "kitten" %>
```

`home.html.erb`を上述のように書き換えると、HTMLをブラウザでレンダリングした結果は以下のように変化します。

<img width="1163" alt="スクリーンショット 2019-09-24 7.44.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/b8ddd876-dce2-1047-b2c9-4554f99b46c7.png">

### 1.2. また、ブラウザのHTMLインスペクタ機能を使って、コメントアウトするとHTMLのソースからも消えていることを確認してみてください。

<img width="1163" alt="スクリーンショット 2019-09-24 7.43.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/43a32296-bfba-a998-dae6-49418df81c88.png">

ネコ画像がある、上述スクリーンショットに対応するHTMLの内容をブラウザのHTMLインスペクタ機能で見ると、結果は以下になります。

```html:home（抜粋）
<div class="container">
    <div class="center jumbotron">
    ...略
    </div>
    <a href="http://rubyonrails.org/"><img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png"></a>
    <img alt="kitten" src="/assets/kitten-44dde42a7808d66c6f314c6587e2c0faabb03d8a3c2c47e4d07e09c08e3c1c6b.jpg">
</div>
```

`home.html.erb`でネコ画像の部分をコメントアウトします。

<img width="1163" alt="スクリーンショット 2019-09-24 7.44.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/b8ddd876-dce2-1047-b2c9-4554f99b46c7.png">

ネコ画像がない、上述スクリーンショットに対応するHTMLの内容は以下になります。erbでコメントアウトすると、ネコ画像に関する部分は、Railsで生成されたHTMLのソースからも確かに消えていました。以下はブラウザのHTMLインスペクタ機能で当該HTMLのソースコードを見たものです。

```html:home（抜粋）
<div class="container">
    <div class="center jumbotron">
    ...略
    </div>
    <a href="http://rubyonrails.org/"><img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png"></a>
</div>
```

Railsで生成されたHTMLのソースにおける、ネコ画像がある場合とネコ画像がない場合の差分は以下のとおりです。

```diff:home（抜粋）
  <div class="center jumbotron">
  ...略
  </div>
  <a href="http://rubyonrails.org/"><img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png"></a>
- <img alt="kitten" src="/assets/kitten-44dde42a7808d66c6f314c6587e2c0faabb03d8a3c2c47e4d07e09c08e3c1c6b.jpg">

```

### 2.1. リスト 5.11のコードを`custom.scss`に追加し、すべての画像を非表示にしてみてください。うまくいけば、Railsのロゴ画像がHomeページから消えるはずです。

`custom.scss`を以下のように書き換えます。

```diff:custom.scss（抜粋）
  #logo:hover {
      color: #fff;
      text-decoration: none;
  }
+
+ img {
+     display: none;
+ }

```

Homeページを更新すると、ブラウザでレンダリングした結果のスクリーンショットは以下のようになります。

<img width="1163" alt="スクリーンショット 2019-09-24 8.14.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/8b93903b-1711-5694-df4a-c711d7b1dde0.png">

確かにRailsロゴの画像がありませんね。

### 2.2. 先ほどと同様にインスペクタ機能を使って、今度はHTMLのソースコードは残ったままで、画像だけが表示されなくなっていることを確認してみてください。 

<img width="1163" alt="スクリーンショット 2019-09-24 8.14.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/8b93903b-1711-5694-df4a-c711d7b1dde0.png">

演習2.1完了時点でのHomeページの表示は以上のとおりでした。当該HTMLのソースコードをブラウザのHTMLインスペクタ機能で見ると、以下のようになっています。

```html:home（抜粋）
<div class="container">
    <div class="center jumbotron">
    ...略
    </div>

    <a href="http://rubyonrails.org/"><img alt="Rails logo" src="/assets/rails-c094bc3a4bf50e5bb477109e5cb0d213af27ad75b481c4df249f50974dbeefe6.png"></a>

</div>
```

確かにRailsロゴの部分のHTMLのソースコードは残っています。一方で、ブラウザにおける当該項目のレンダリング結果は以下の通りになりました。

<img width="95" alt="スクリーンショット 2019-09-24 18.06.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/61fc072e-f05c-fa34-7919-09eab9695d54.png">

幅`0px`でレンダリングされているようです。

## パーシャル

Railsにおける重要な原則として、DRY(Don't Repeat Yourself)というものがあります。パーシャルという機能は、主に「類似する記述のコードを一つにまとめることにより、DRYの実現に寄与する」という目的を持ちます。

それでは実際に使ってみましょう。まず、`app/views/layouts/application.html.erb`を以下のように書き換えます。

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

以下2行がパーシャルです。まずは、`shim`に対するパーシャルから。

```erb:
<%= render 'layouts/shim' %>
```

続いて、`header`に対するパーシャルです。

```erb:
<%= render 'layouts/header' %>
```

パーシャルが動作するためには、当然ながら対応するファイルとコンテンツを記述しなければなりません。今回においては、以下の2つのファイルが必要となります。

* `app/views/layouts/_shim.html.erb`
* `app/views/layouts/_header.html.erb`

```erb:app/views/layouts/_shim.html.erb
<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
  </script>
<![endif]-->
```

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

`header`があれば`footer`もあります。ここまで意図的に定義されていませんでしたが、今の段階で、パーシャルによって`footer`を定義することとします。

```erb:app/views/layouts/_footer.html.erb
<footer class="footer">
  <small>
    The <a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
    by <a href="http://www.michaelhartl.com/">Michael Hartl</a>
  </small>
  <nav>
    <ul>
      <li><%= link_to "About",   '#' %></li>
      <li><%= link_to "Contact", '#' %></li>
      <li><a href="http://news.railstutorial.org/">News</a></li>
    </ul>
  </nav>
</footer>
```

`footer`パーシャルを追加した時点での`app/views/layouts/application.html.erb`の内容は以下の通りとなります。

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

スタイルシートも若干書き換えます。

```diff:app/assets/stylesheets/custom.scss
+ /* footer */
+
+ footer {
+     margin-top: 45px;
+     padding-top: 5px;
+     border-top: 1px solid #eaeaea;
+     color: #777;
+ }
+ 
+ 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: 15px;
+ }
```

* 古いバージョンのMSIE用のshimをパーシャルに置換え
* `header`をパーシャルに置換え
* `footer`をパーシャルで新規追加

ここまでの変更を反映した時点でのHomeページの表示は、以下のようになります。

<img width="1166" alt="スクリーンショット 2019-09-24 18.33.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/d62333f1-5d22-c68b-5d73-72992ee77005.png">

様になっていますねぇ。

## 演習 - パーシャル

### 1. Railsがデフォルトで生成する`head`タグの部分を、[リスト 5.18](https://railstutorial.jp/chapters/filling_in_the_layout?version=5.1#code-rails_default_head)のように`render`に置き換えてみてください。

```diff:app/views/layouts/application.html.erb（抜粋）
    <head>
      <title><%= full_title(yield(:title)) %></title>
-     <%= csrf_meta_tags %>
-     <%= stylesheet_link_tag    'application', media: 'all',
-                                'data-turbolinks-track': 'reload' %>
-     <%= javascript_include_tag 'application',
-                                'data-turbolinks-track': 'reload' %>
+     <%= render 'layouts/rails_default' %>
      <%= render 'layouts/shim' %>
    </head>
```

この時点でHomeページを読もうとするとエラーになりますね。

```
Processing by StaticPagesController#home as HTML
  Rendering static_pages/home.html.erb within layouts/application
  Rendered static_pages/home.html.erb within layouts/application (80.3ms)
Completed 500 Internal Server Error in 366ms


  
ActionView::Template::Error (Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
  * "/var/www/sample_app/app/views"
):
    2: <html>
    3:   <head>
    4:     <title><%= full_title(yield(:title)) %></title>
    5:     <%= render 'layouts/rails_default' %>
    6:     <%= render 'layouts/shim' %>
    7:   </head>
    8:   <body>
  
app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__4350315865393828314_70305832847700'
```

<img width="1185" alt="スクリーンショット 2019-09-24 21.38.18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/7a3e755d-7e43-c28e-7aca-c2a5c8f4e2d8.png">

### 2. リスト 5.18のようなパーシャルはまだ作っていないので、現時点ではテストは`red`になっているはずです。実際にテストを実行して確認してみましょう。

開発環境のDockerコンテナにてテストを実行します。

```
# rails test
Running via Spring preloader in process 715
...略

ERROR["test_should_get_about", StaticPagesControllerTest, 0.6039791999937734]
 test_should_get_about#StaticPagesControllerTest (0.60s)
ActionView::Template::Error:         ActionView::Template::Error: Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/www/sample_app/app/views"
        
            app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__674720961164781611_69850764501740'
            test/controllers/static_pages_controller_test.rb:27:in `block in <class:StaticPagesControllerTest>'

ERROR["test_should_get_home", StaticPagesControllerTest, 9.42968019998807]
 test_should_get_home#StaticPagesControllerTest (9.43s)
ActionView::Template::Error:         ActionView::Template::Error: Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/www/sample_app/app/views"
        
            app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__674720961164781611_69850764501740'
            test/controllers/static_pages_controller_test.rb:15:in `block in <class:StaticPagesControllerTest>'

ERROR["test_should_get_contact", StaticPagesControllerTest, 9.47271329999785]
 test_should_get_contact#StaticPagesControllerTest (9.47s)
ActionView::Template::Error:         ActionView::Template::Error: Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/www/sample_app/app/views"
        
            app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__674720961164781611_69850764501740'
            test/controllers/static_pages_controller_test.rb:33:in `block in <class:StaticPagesControllerTest>'

ERROR["test_should_get_help", StaticPagesControllerTest, 9.521536000000197]
 test_should_get_help#StaticPagesControllerTest (9.52s)
ActionView::Template::Error:         ActionView::Template::Error: Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/www/sample_app/app/views"
        
            app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__674720961164781611_69850764501740'
            test/controllers/static_pages_controller_test.rb:21:in `block in <class:StaticPagesControllerTest>'

ERROR["test_should_get_root", StaticPagesControllerTest, 9.551777899992885]
 test_should_get_root#StaticPagesControllerTest (9.55s)
ActionView::Template::Error:         ActionView::Template::Error: Missing partial layouts/_rails_default with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :coffee, :jbuilder]}. Searched in:
          * "/var/www/sample_app/app/views"
        
            app/views/layouts/application.html.erb:5:in `_app_views_layouts_application_html_erb__674720961164781611_69850764501740'
            test/controllers/static_pages_controller_test.rb:10:in `block in <class:StaticPagesControllerTest>'

  5/5: [===================================] 100% Time: 00:00:09, Time: 00:00:09

Finished in 9.55596s
5 tests, 0 assertions, 0 failures, 5 errors, 0 skips
```

いきなり5つもエラーが出るようになってしまって面食らいます。しかし、冷静に見ていくと、「`about`・`home`・`contact`・`help`・`root`それぞれに対し、いずれも`layouts/_rails_default`というパーシャルがない」という意味のエラーです。これら5つのページにおいて、`head`要素の内容を定義しているのはいずれも`app/views/layouts/application.html.erb`なので、問題があるのは`app/views/layouts/application.html.erb`内の記述ということになります。

足りないのは何か。`app/views/layouts/_rails_default.erb`ですね。それでは書いていきましょう。

### 3. `layouts`ディレクトリに`head`タグ用のパーシャルを作成し、先ほど退避しておいたコードを書き込み、最後にテストが`green`に戻ることを確認しましょう。

```erb:app/views/layouts/_rails_default.erb
<%= csrf_meta_tags %>
<%= stylesheet_link_tag    'application', media: 'all',
                           'data-turbolinks-track': 'reload' %>
<%= javascript_include_tag 'application',
                           'data-turbolinks-track': 'reload' %>
```

テストの結果はどうなるでしょうか。開発環境のDockerコンテナにて実行してみます。

```
# rails test
Running via Spring preloader in process 730
/var/www/sample_app/db/schema.rb doesn't exist yet. Run `rails db:migrate` to create it, then try again. If you do not intend to use a database, you should instead alter /var/www/sample_app/config/application.rb to limit the frameworks that will be loaded.
Started with run options --seed 61904

  5/5: [===================================] 100% Time: 00:00:01, Time: 00:00:01

Finished in 1.67973s
5 tests, 9 assertions, 0 failures, 0 errors, 0 skips
```

よし！きちんとテストが通りました。

ここまでの変更を反映した時点でのHomeページの表示は、以下のようになります。

<img width="1164" alt="スクリーンショット 2019-09-24 21.57.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323778/9d4b6fd5-7515-2b12-a11a-29420fec898b.png">