Rails Tutorial 第五章 簡易まとめ レイアウトを作成

5.1

・各ページのレイアウトを完成(filling-in-layout branch)

5.1.1 ナビゲーション

まずはサンプルアプリケーションにリンクとスタイルを追加するために、サイトのレイアウトファイルapplication.html.erb にHTML構造を追加、更新

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>

Home.hrml.erbも作成

app/views/static_pages/home.html.erb
<div class="center jumbotron">
  <h1>Welcrb:ome 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/' %>

!--[if lt IE 9]

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

Application.html.erbのコードには、上のような奇妙な構文が含まれています
<!--[if lt IE 9]>

これは、Microsoft Internet Explorer (IE) のバージョンが9より小さい場合 (if lt IE 9) にのみ、囲まれている行を実行します。この風変わりな文法 [if lt IE 9] は、Railsの一部ではありません。これは実は、条件付きコメントと呼ばれるもので、今回のような状況のためにInternet Explorerで特別にサポートされています。これにより、Firefox、Chrome、Safariなどの他のブラウザに影響を与えずに、IEのバージョンが9未満の場合にのみHTML5 shimを読み込めるため、非常に好都合です。

コマンドラインで画像をダウンロード(curl)

home.htmlの2つ目のlink_toでは、引数として画像ファイルのパスと任意のオプションハッシュをとるimage_tagヘルパーの能力が示されています。
このヘルパーでは、シンボルを使ってalt属性などを設定できます。一方で画像を表示するためには、rails.pngというRailsのロゴ画像ファイルを加える必要があります。Ruby on Rails公式ページの https://railstutorial.jp/rails.png から画像をダウンロードして、app/assets/images/ディレクトリにおいてください。

$ curl -o app/assets/images/rails.png -OL railstutorial.jp/rails.png

リスト 5.2で image_tagヘルパーを使っているので、Railsは該当する画像ファイルを、アセットパイプラインを通してapp/assets/images/ディレクトリの中から探してくれます

5.1.2 Bootstrap と CSS

5.1.1ではたくさんのCSSクラスを関連付けました。これをフレームワークBootstrapで洗練されたWebデザインとユーザーインターフェイス要素を追加していこう
注目すべき点は、Bootstrapを使うことでアプリケーションをレスポンシブデザイン (Responsive Design) にできるということです

Bootstrapの使用準備

1,gemfileに書き込む
gem 'bootstrap-sass', '3.3.7'

2,bundle install

3,CSSを動かす為のファイル生成
$ touch app/assets/stylesheets/custom.scss
※Asset Pipeline (5.2)の一部であり、このディレクトリに置かれたスタイルシートはapplication.cssの一部としてWebサイトのレイアウトに読み込まれます。さらに、ファイル名のcustom.scssには.scssという拡張子も含まれています。この拡張子は「Sass (Sassy CSS)」と呼ばれるCSSを拡張した言語で、アセットパイプラインはこのファイルの拡張子を見て、Sassを処理できるようにしています

4,Bootstrap CSSを追加する
@importを使って、Bootstrap (とそれに関連するSprockets) を読み込み

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

5,サーバーを再起動しアップリケーションに反映

image.png

6,CSSをいじってみる

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

/* typography */
/*洗練されたタイポグラフィーを利用するためのCSSを追加する*/

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;
}
/* header */
/* サイトロゴにCSSを追加*/
#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;
}

image.png

パーシャル(Partial)

・まずそもそもパーシャルとは。

render メソッドに :partial パラメータを渡すことでパーシャル(部分テンプレート)をレンダリングする。こと

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>

<%= render 'layouts/shim' %>
renderと呼ばれるRailsヘルパー呼び出しだけを使って、HTML shimのスタイルシート行を置換していてapp/views/layouts/_shim.html.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]-->

shimだけではなくheaderのパーシャルも行われている。

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>

※!パーシャルのファイル名はパーシャルの名前の先頭にアンダースコアを付加したものとなる!※

パーシャルの作成方法がわかりましたので、今度はヘッダーに対応するフッタを逆の流れでかつ、同じ方法で追加してみる

1,先にパーシャルファイルを作って

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>

2,Application.html.erbにrenderとして渡す

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>

CSSで整える

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

image.png

更に。。。

 <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>

titleタグ以降の情報も”_rails_default.html.erb”にまとめちゃおう

  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= render 'layouts/rails_default' %>
    <%= render 'layouts/shim' %>
  </head>

5.2.2 Sass

Sass は、スタイルシートを記述するための言語であり、CSSに比べて多くの点が強化されています。この節では、Sassが提供する2つの重要な機能、ネストと変数について説明します。

SassはSCSSというフォーマットに対応しています (.scssという拡張子はSCSSであることを表します)。SCSSは厳密な意味で、CSS本体を抽象化したフォーマットです。つまり、SCSSはCSSに新しい機能を追加しただけで、全く新しい構文を定義したようなものではないということです15。このため、有効なCSSファイルは、すべてSCSSファイルとしても扱うことができ、既存の記法ルールを使っているプロジェクトにとっても互換性のある便利なフォーマットになっています。本書の例では、Bootstrapの恩恵を得るために、私達は最初からSCSSを使っています。Railsのアセットパイプラインは、.scssという拡張子を持つファイルをSassを使って自動的に処理してくれます。このため、custom.scssファイルはSassプリプロセッサによって前処理され、その後ブラウザへの配信に備えてパッケージ化されます

ネスト

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

.center {
  text-align: center;
}

.center h1 {
  margin-bottom: 10px;
}
.
.
#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;
}
.
.
/* 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;
}

上のコードは、Sassを使って次のように書き換えることができます。

.center {
  text-align: center;
  h1 {
    margin-bottom: 10px;
  }
}
.
.
#logo {
  float: left;
  margin-right: 10px;
  font-size: 1.7em;
  color: #fff;
  text-transform: uppercase;
  letter-spacing: -1px;
  padding-top: 9px;
  font-weight: bold;
  &:hover {
    color: #fff;
    text-decoration: none;
  }
}
.
.
footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: #777;
  a {
    color: #555;
    &:hover {
      color: #222;
    }
  }
  small {
    float: left;
  }
  ul {
    float: right;
    list-style: none;
    li {
      float: left;
      margin-left: 15px;
    }
  }
}

変数

Sassでは、冗長なコードを削除し、より自由な表現を可能にするために、変数が定義できるようになっています

例)同じ色のコード使用があった場合

$light-gray: #777;
.
.
.
h2 {
  .
  .
  .
  color: $light-gray;
}
.
.
.
footer {
  .
  .
  .
  color: $light-gray;
}

フレームワークで定義されている変数はBootstrapページの「LESS変数一覧」で参照することができます。このWebサイトでは、SassではなくLESSを使って変数が定義されていますが、bootstrap-sassというgemを使えば、Sassでも同様の変数が使えるようになります。例えばLESSではアットマーク@を使っているのに対して、Sassはドルマーク$を使っていることはすぐにわかります。話を戻して、Bootstrapの変数の一覧表を見ると、薄い灰色に対して次の変数名が与えられることに気が付きます。

@gray-light: #777;
これはつまり、bootstrap-sassというgemを使えば、SCSSでも同様に$gray-lightという変数が使えることを意味しています。先ほど定義した$light-grayというカスタム変数の代わりに、用意された変数を使ってみましょう。

h2 {
  .
  .
  .
  color: $gray-light;
}
.
.
.
footer {
  .
  .
  .
  color: $gray-light;
}

5.3レイアウトのリンク

サイトのレイアウトが美しく仕上がったので、今度は’#’で代用していたリンクを書き換えてみましょう。
まず、aboutページへのURLは /static_pages/about よりも /about の方がよいでしょう。さらに、Railsでは次のようなコードでは名前付きルートを使うのが慣例となっています。

<%= link_to "About", about_path %>

上のようにすることでコードの意味がわかりやすくなり、about_pathの定義を変えればabout_pathが使われているすべてのURLを変更できるため、柔軟性が高まります。

5.3.1 contactページ実装

app/views/static_pages/contact.html.erb
 <% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
  Contact the Ruby on Rails Tutorial about the sample app at the
  <a href="https://railstutorial.jp/contact">contact page</a>.
</p>

他は略

5.3.2 RailsのルートURL

本項では、名前付きルートをサンプルアプリケーションの静的ページで使うために、ルーティング用のファイル (config/routes.rb) を編集していきます。まずは、3.4.4で定義したHomeページのルーティングについて見直していきましょう。 

root 'static_pages#home'

rootメソッドを使ってルートURL "/" をコントローラーのアクションに紐付けていました。ルートURLのようなルーティングを定義することの効果は、ブラウザからアクセスしやすくすることだけではありません。それ以外にも、生のURLではなく、名前付きルートを使ってURLを参照することができるようになります。例えばルートURLを定義すると、root_pathやroot_urlといったメソッドを通してURLを参照することができます。ちなみに前者はルートURL以下の文字列を、後者は完全なURLの文字列を返します。

root_path -> '/'
root_url  -> 'http://www.example.com/'

他、HelpページやAboutページ、Contactページなどの名前付きルートを定義していきましょう

get 'static_pages/help'

このように変換します。

get '/help', to: 'static_pages#help'

このようにgetルールを使って変更すると、GETリクエストが /help に送信されたときにStaticPagesコントローラーのhelpアクションを呼び出してくれるようになります。また、ルートURLのときと同様に、help_pathやhelp_urlといった名前付きルートも使えるようになります。

help_path -> '/help'
help_url  -> 'http://www.example.com/help'

まとめて

config/routes.rb
 Rails.application.routes.draw do
  root 'static_pages#home'
  get  '/help',    to: 'static_pages#help'
  get  '/about',   to: 'static_pages#about'
  get  '/contact', to: 'static_pages#contact'
end

※なお、’static_pages/home’という以前のルールを削除している点に注意してください。今後は常にroot_pathまたはroot_urlを使っていきます。

古くなったテストも更新する

test/controllers/static_pages_controller_test.rb
 require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get static_pages_home_url
    assert_response :success
    assert_select "title", "Ruby on Rails Tutorial Sample App"
  end

  test "should get help" do
    get static_pages_help_url
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get static_pages_about_url
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end

  test "should get contact" do
    get static_pages_contact_url
    assert_response :success
    assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
  end
end

test/controllers/static_pages_controller_test.rb
 require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  test "should get home" do
    get root_path
    assert_response :success
    assert_select "title", "Ruby on Rails Tutorial Sample App"
  end

  test "should get help" do
    get help_path
    assert_response :success
    assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
  end

  test "should get about" do
    get about_path
    assert_response :success
    assert_select "title", "About | Ruby on Rails Tutorial Sample App"
  end

  test "should get contact" do
    get contact_path
    assert_response :success
    assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
  end
end

get 名前付きルート
とする

5.3.3 名前付きルート

ルートを定義したことにより、レイアウトの中で名前付きルートが使えるようになりました。早速、link_toメソッドの2番目の引数で、適切な名前付きルートを使ってみましょう。例えば次のコードの場合、

<%= link_to "About", '#' %>

このように置き換えます。

<%= link_to "About", about_path %>

他も同様です。
headerパーシャル _header.html.erb から取り掛かります。headerパーシャルでは、Web共通の慣習に従って、ロゴにもHomeページへのリンクを追加します。

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

つづいてフッダー

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",   about_path %></li>
      <li><%= link_to "Contact", contact_path %></li>
      <li><a href="http://news.railstutorial.org/">News</a></li>
    </ul>
  </nav>
</footer>

5.3.4 リンクが正常かテスト 統合テスト

統合テストとは、アプリケーションの動作を端から端まで (end-to-end) シミュレートしてテストすることができる
まずは、site_layoutというテストのテンプレートを生成するところから始めてみます。

$ rails generate integration_test site_layout
      invoke  test_unit
      create    test/integration/site_layout_test.rb

※このとき、Railsは渡されたファイル名の末尾に _test という文字列を追加することに注目してください。

Railsの統合テストでは、下のステップをコードに落とし込んでいくことになります

1 ルートURL (Homeページ) にGETリクエストを送る.

2 正しいページテンプレートが描画されているかどうか確かめる.

3 Home、Help、About、Contactの各ページへのリンクが正しく動くか確かめる.

test/integration/site_layout_test.rb
 require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest

  test "layout links" do
    get root_path
    assert_template 'static_pages/home'#Homeページが正しいビューを描画しているかどうか確かめ
    assert_select "a[href=?]", root_path, count: 2
    assert_select "a[href=?]", help_path
    assert_select "a[href=?]", about_path
    assert_select "a[href=?]", contact_path
  end
end

assert_selectメソッドの高度なオプションを使っていて、Railsは自動的にはてなマーク "?" をabout_pathに置換していて、これにより、次のようなHTMLがあるかどうかをチェックすることができます。

<a href="/about">...</a>

一方で、ルートURLへのリンクは2つあることを思い出してください (1つはロゴに、もう1つはナビゲーションバーにあります)。下の様に指定する

assert_select "a[href=?]", root_path, count: 2

追加した統合テストが通るかどうかは、次のようにRakeタスクを実行することで試すことができます。

green
$ rails test:integration

統合テストが成功したら、今度はすべてのテストを流して greenするかどうか確かめてみてください。

green
$ rails test

レイアウトのリンクをテストする統合テストが追加されたことで、リンクに間違った変更が加えられたらすぐに気付けるようになりました。

5.4 ユーザー登録最初のステップ

ユーザー登録ページの作成
モデリングは6章、ユーザー登録は7章

5.4.1 Usersコントローラ

$ rails g controller Users new
      create  app/controllers/users_controller.rb
       route  get 'users/new'
      invoke  erb
      create    app/views/users
      create    app/views/users/new.html.erb
      invoke  test_unit
      create    test/controllers/users_controller_test.rb
      invoke  helper
      create    app/helpers/users_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss

5.4.2 ユーザー登録用URL(Signupページ)

自動生成されたファイルを編集して名前付きルートが
使える様にする

config/routes.rb
 Rails.application.routes.draw do
  root 'static_pages#home'
  get  '/help',    to: 'static_pages#help'
  get  '/about',   to: 'static_pages#about'
  get  '/contact', to: 'static_pages#contact'
  get  '/signup',  to: 'users#new'
end
test/controllers/users_controller_test.rb
 require 'test_helper'

class UsersControllerTest < ActionDispatch::IntegrationTest

  test "should get new" do
    get signup_path
    assert_response :success
  end
end

次に、新しく定義された名前付きルートを使って、Homeページのボタンに適切なリンクを追加します。他のルートと同様、get ’/signup’と記述したことでsignup_pathという名前付きルートができた。

rb: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!", signup_path, class: "btn btn-lg btn-primary" %>
</div>

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

最後に、signupページ用のビューを編集します。

app/views/users/new.html.erb
 <% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>This will be a signup page for new users.</p>

都度、テスト、コミットは忘れず。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.