Posted at

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

More than 5 years have passed since last update.


やること


  • アプリケーションにBootstrapフレームワークを組み込み、カスタムスタイルを追加

  • 作成するページへのリンクをレイアウトに追加

  • パーシャルRailsのルーティング、Asset PipelineSass


  • RSpecテクニックを用いたリファクタリング


構造を追加する



  • Bootstrap


    • Twitter社のオープンソースのWebデザインフレームワーク



  • 画面の変更


    • リンク等のレイアウト変更

    • 各種ページへのリンクを追加

    • サインアップページへのリンクを追加




レイアウト変更のためのブランチを作成

$ git checkout -b filling-in-layout



ナビゲーションの追加


  • リンクとスタイルを追加


    • レイアウトファイルのapplication.html.erbにHTML構造を追加


    • <div>タグの追加、CSSクラスの追加、サイトナビゲーションの追加




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






  • <%= link_to "Home", '#' %>


    • リンクを生成するヘルパー

    • 第1引数:リンクテキスト

    • 第2引数:URL

    • 第3引数(オプション):オプションハッシュ。HTMLオプションを柔軟に追加できる




  • <nav>タグ


    • 内部がナビゲーションリンクであることを表す


    • <ul>タグのnavpull-rightクラスはBootstrapにおいて特別な意味を持つ




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>


  • レイアウト修正後の画面



  • Home画面の修正



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/' %>




  • hero-unitbtnbtn-primaryクラス



    • Bootstrapにおいて特別な意味を持つ




  • image_tagヘルパー



    • imgタグの生成

    • 第1引数:画像ファイル名

    • 第2引数:ハッシュ




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 PipelineSass言語をサポート


    • bootstrap-sassLESSSassに変換する




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

```


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をインクルードする




app/assets/stylesheets/custom.css.scss

@import "bootstrap";



  • この時点での画面表示



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



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



  • 画面表示の変更を確認




  • サイトのテキストの外観を変更


    • 洗練されたタイポグラフィーを利用




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



  • サイトのテキストを変更した後の画像




  • サイトロゴのスタイル変更


    • テキストを大文字に変換

    • サイズ、色、配置の変更




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



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


パーシャル(partial)



  • 現状の問題点



    • HTML shimだけで3行使ってしまっている



      • IE特有の文法を使用してしまっている



    • HTMLヘッダーは論理的な単位を形成するため、一箇所にまとめる必要がある




  • パーシャル機能によって整理する



    • renderを使い、IE固有の設定およびヘッダー部分の記述を変更




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というファイルを検索してその内容を評価し、結果をビューに挿入

    • パーシャルの命名規則として、ファイル名に_をつける




app/views/layouts/_shim.html.erbでパーシャルを作成

<!--[if lt IE 9]>

<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->


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>


  • フッターの作成


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>


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>


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


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


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



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


SassとAsset Pipeline



  • Asset Pipeline


    • CSS、Javascript、画像などの静的コンテンツの生産性と管理を大幅に強化する機能




  • Sass


    • CSS生成ツール




Asset Pipeline


  • 主要な機能


    1. アセットディレクトリ

    2. マニフェストファイル

    3. プリプロセッサエンジン





  • アセットディレクトリ


    • Rails3.0以前のバージョン


      • public/stylesheets

      • public/javascripts

      • public/images



    • Rails3.1以降のバージョン - 目的別に静的ファイルを分類。それぞれにstylesheetsjavascriptsimagesディレクトリが存在する



      • app/assets:現在のアプリケーション固有のアセット


      • lib/assets:自身の開発チームによって作成されたライブラリ用のアセット


      • vendor/assets:サードパーティーのアセット








  • マニフェストファイル


    • アセットディレクトリのファイルをどのように1つのファイルにまとめるかをRailsに指示

    • 実際にまとめるのはSprockets gem

    • CSSとJavaScriptには適用されるが、画像ファイルには適用されない




  • *= require_tree .



    • app/assets/stylesheetsディレクトリの全てのCSSをアプリケーションCSSにインクルードすることを指す




  • *= require_self


    • CSSの読み込みの際に、application.css自身もインクルードする



  • 今回は特に変更しない



マニフェストファイル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の表記:.centerへのルール

.center {

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


Sassでの表記:.centerをネストして記載

.center {

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


通常の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;
}



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

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



フッターの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変数一覧を参照


      • bootstrap-sassというgemを使用することで、Sassでも同様の変数が使える






通常のCSS:#999を複数個所で使用

h2 {

color: #999;
}
footer {
color: #999;
}


SCSS:#999を変数として定義

$lightGray: #999;

h2 {
color: $lightGray;
}
footer {
color: $lightGray;
}


SCSS:Bootstrapフレームワークで定義している変数を利用

h2 {

color: $grayLight;
}
footer {
color: $grayLight;
}


  • ネスト・変数を使用して、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




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'






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になる




  • homeconfig/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になる


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メソッドの変更


    • ヘッダーのパーシャルとフッターのパーシャルを修正

    • 当変更後、HomeHelpAboutContactへのリンクが有効になる




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のテスト内容が冗長で繰り返しが多くなってきている


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ブロックを使用して冗長箇所を除去する




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!'" doexpect(page).to have_content('Sample App')は同じことを言っている



    • itメソッドの別のものを使用




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によって自動的に読み込まれる




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


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



  • 上記を踏まえて、テストクラスをリファクタリング


    • 修正後にテストを実行して、正常終了することを確認




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コントローラ


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


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


テスト用ファイルの作成

$ rails generate integration_test user_pages

invoke rspec
create spec/requests/user_pages_spec.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のルートを追加




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


  • ユーザ登録ページのスタブを作成


    • テストを実施し、正常終了することを確認




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へのリンクを修正


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/' %>



コミット


コミット、デプロイ

$ 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にて設定することで、同じようなテストケースの記載を省くことができる




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など、他のページにも同様に適用




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


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




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



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


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



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

include ApplicationHelper