13
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Ruby on Rails チュートリアル 第5章 HTML CSS SCSS Bootstrapやアセットパイプラインを解説

Last updated at Posted at 2018-12-17

#近況報告

エンジニア転職成功しました。YouTubeもはじめました。

前回の続き

著者略歴
YUUKI
ポートフォリオサイト:Pooks
現在:RailsTutorial2周目

#第5章 難易度 ★★ 3時間
挫折しないRailsチュートリアルの進め方を先にお読みください↓↓

Railsチュートリアルで挫折しない3つのポイント

この章ではHTML/CSSの基礎からアセットパイプラインの概要、Sass、Bootstrapの使い方
効率よくコーディングする為のパーシャル、統合テストなどアプリケーション作成に必要な基礎スキルを身に付ける。

#レイアウトを作成する

この章では、デザイン関係の部分を弄る。
WebデザインフレームワークであるBootstrapを使い、パーシャル機能を使ってレイアウトのコードを整える。さらに、統合テストも取り扱っていくとのこと。

##構造を追加する

ユーザーインターフェースの概要をできるだけ早い段階で把握しておくために、「モックアップ」を作成する。
このモックアップは、実装後のアプリケーションの外観をスケッチして使っていく。

Homeページのモックアップ

image.png

出典:図 5.1: サンプルアプリケーションのHomeページのモックアップ

###ナビゲーション

サンプルアプリケーションにリンクとスタイルを追加するために、application.html.erbにHTML構造を追加する。主にdivタグやCSSクラス、サイトナビゲーションの起点となる領域の追加も含まれる。

application.html.erb
<DOCTYPE html>
<html>
  <head>
    <title><%= full_title(yield(:title)) %></title>
    <%= scrf_meta_tags %>
    <%= stylesheet_link_tag     'application', media: 'all',
                                'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application',
                              'data-turbolinks-track':   'reload' %>
    <!--[if It 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>

長いけど、まず重要なコードはこれ。

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

このJavaScriptのコードで、旧式のIEでもサポート出来るようにする。

application.html.erb
<!--[if It IE 9]>

この部分はIEのバージョンが9より小さい場合、囲まれている部分を実行する。
これを条件付きコメントと言う。

バージョンが9未満の場合のみHTML5 shimを読み込める。

headerタグの部分。

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

classとidが幾つか割り振られている。

HTML5では、全体でdivタグを扱うのではなく、header要素、nav要素、section要素が新たに追加されたのでこれを使う。
headerタグとdivタグにcontainerというクラスが与えられているが、これはBootstrapにおいても特別な意味を持つ。

application.html.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>

link_toは埋め込みRubyであり、第一引数にテキスト、第二引数にURLを付ける。
#はWebデザインで一般に使われるスタブ用のURLである。

第三引数はオプションハッシュ。CSS id logoを指定している。

続いて、navタグを見てみる。

application.html.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>

ulタグの三つのclassnav navbar-nav navbar-rightがBootstrapにおいても特別な意味を持つ。

どうやらBootstrapのCSSを追加したときに、この三つのスタイルが自動的に適用される。

ブラウザからソースを見た際、上記のHTMLは以下のように変化する。

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

これはRailsが埋め込みRubyを評価しているため、ブラウザに返されるのはHTMLに変わる。

そして重要なのがこれ

application.html.erb
    <div class="container">
      <%= yield %>
    </div>

containerクラスもBootstrapで適用される。
さらに、yieldメソッドはWebサイトのレイアウトページごとの内容を挿入する。

これである程度のレイアウトは完成。

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

homeページのレイアウトも確認。
これらで使っているクラスは全てBootstrapに置いて特別な意味を持つ。

2番目のlink_toでは画像ファイルのパスと任意のオプションハッシュをとるimage_tagヘルパーの能力が示される。このヘルパーでは、シンボルを使ってalt属性などを設定できる。

ここで、link_toで設定している画像をインストールする。
Cloud9の場合、curl(カール)コマンドで簡単に画像を取得できる。

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

image_tagヘルパーを使って画像ファイルを読み込むので、画像をアセットパイプラインを通してapp/assets/images/ディレクトリの中から探してくれる。

んで、rails sでサーバー起動して確認してみる。
今回自分なりに弄ってみた。

スクリーンショット 2018-12-15 12.00.01.png

image_tagの効果を確かめるべく、HTMLソースを確認。

<img alt="Rails logo" src="/assets/yuuki-e83954ed50d243b8f3edb6aee76f03768aed99b6436f49906ab2f8c56e6d32c9.png">

画像の所を確認して見入るとこんな表示になってる。
このe8395~ってのは、例えばこの画像ファイルを新しい画像に更新した時、ブラウザ内に保存されたキャッシュを意図的にヒットさせないようにする仕組みとのこと。
また、src属性にはimagesというディレクトリ名が含まれていない点にも注目。

これはassetsディレクトリ内の他のディレクトリでも同様で、高速化のための仕組み。

というのも、この仕組みを使うことでassetsディレクトリ直下の画像をapp/assets/imagesディレクトリにある画像と紐づけている。
ブラウザからみると、全てのファイルが同じディレクトリにあるように見えるようになり、階層構造で言う所の深い部分のファイルまでロードせずに済み、フラットなディレクトリ構成を実現。ファイルをより高速にブラウザに渡すことが可能となる。

ここで、演習の通り猫ちゃん画像をダウソして表示してみる。

スクリーンショット 2018-12-15 13.01.49.png

ふむ。

###BootstrapとカスタムCSS

先ほどの部分でHTML要素にCSSクラスを関連付けたが、これらの殆どはBootstrap用のクラスである。
このBootstrapはカスタムCSSルールと合わせて使用する。
Bootstrapの利点はレスポンシブデザインにできるという点。

という訳で早速Bootstrapを追加する。

gemを使ってインストール。

gem 'bootstrap-sass', '3.3.7'
$ bundle install

ここで、カスタムCSSを動かすた目にカスタムCSSファイルを作成。

touch app/assets/stylesheets/custom.scss

ここで紹介されているapp/assets/stylesheets/はAsset Pipelinenの一部。
このディレクトリに置かれたスタイルシートは、application.cssの一部としてWebサイトのレイアウトに読み込まれる。

また、scssという拡張子はSassと呼ばれるCSS拡張言語で、アセットパイプラインはこのファイルの拡張子を見て、Sassを処理できるようにしている。(bootstrap-sass gemが動作するために必要)

custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";

@importを使ってbootstrapを読み込ませる。

これでhomeページを確認。

何も指定してないのに勝手にデザインが出来あがるという。

指示通りにcustom.scssに以下を記入。

custom.scss
/* universal */

body {
  padding-top: 60px;
}

section {
  overflow: auto;
}

textarea {
  resize: vertical;
}

.center {
  text-align: center;
}

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

スクリーンショット 2018-12-15 15.07.46.png

CSSの形式は一貫しており、CSSルールでは一般に
class,id,HTMLタグ,またはそれらの組み合わせ、のいずれかを指定し、
その後ろにスタイリングコマンドを記述する。例えば次のコマンド

custom.scss
body {
 padding-top: 60px;
}

bodyセレクタのpadding-topプロパティに60pxという値を設定。
つまり、bodyの上側に60pxの余白を追加するという意味だ。ただし、headerタグにnavbar-fixed-topクラスが付与されている為、Bootstrapがナビゲーションバーをページ上部に固定し、その下に60pxの余白が与えられる。

次にこちらのコード

custom.scss
.center {
 text-align: center;
}

ここで.が付いている理由は、centerがクラスであるということ。先ほどのbodyはタグなので.は付けない。
ちなみにidにセレクタを設定する場合は先頭に#を付ける。

上記のコードでcenterクラスの内側の要素が全て中央揃えになる。

さらにこちらのコードを追加。

custom.scss
/* タイポグラフィ */

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

これはタイポグラフィと言って、テキストや画像の体裁を決めるもの。予め書いておくことで、個別で文字サイズなどを指定せずに済む。

元々Bootstrapには洗練されたタイポグラフィを利用できるCSSルールがあるが、今回はこのように追加でテキストの見栄えを変えてみる。

ここでhomeページを確認してみると、さらに洗練されたデザインになっている。

さらに下記のコードを追加。

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

colorプロパティの値「#fff」は白色。
HTMLの色は16進数の三つの数値の組み合わせで表現され、,,の順で、三原色にコード化することができる。

*fは16進数で15に値する。また、本来whiteは#ffffffだがここでは短縮記法にしている。

ここで、演習をやってみる。

猫画像をコメントアウトしてみる。
(今回はプロフィール画像をコメントアウトする)

home.html.erb
<%#= link_to image_tag("yuuki.png", alt: "Rails logo"),
            'https://twitter.com/bitcoinjpnnet', target: "_blank" %>

このように埋め込みRubyのコードは%と=の間に#を記入することで簡単にコメントアウト出来る。

次にimgセレクタをdisplay noneしてみる。

custom.scss
img {
 display: none;
}

全ての画像が消えていることを確認。

###パーシャル

先程のHTML修正(shim)ではそれだけでも3行を有し、無駄が多い。これを上手く隠したり、論理的な単位を形成する為、一箇所にコードをまとめる必要がある。
その為に、Railsではpartialと呼ばれている機能を使う。

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>

パーシャルの読み込みにはrenderメソッドを使う。

パーシャルでは、ファイル名の先頭に_(アンダースコア)を付与する普遍的な命名規則がある。
_shim.html.erb_header.html.erbというファイル名でパーシャルを作成してみる。

_shim.html.erb
<!--[if lt IE 9]>
  <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
  </script>
<![endif]-->
_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>

さらに、footer用のパーシャルも作成。

_footer.html.erb
<footer class="footer">
  <smail>
    The <a href="https://railstutorial.jp/">YUUKIのポートフォリオ</a>
    by <a href="https://twitter.com/bitcoinjpnnet">YUUKI</a>
  </smail>
  <nav>
    <ul>
      <li><%= link_to "About",  '#' %></li>
      <li><%= link_to "Contact",  '#' %></li>
      <li><a href="https://webnewage.com/">YUUKIのブログ</a></li>
    </ul>
  </nav>
</footer>

footer用のscssも追加。

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 smail {
  float: left;
}

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

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

演習通りにrails_defaultパーシャルも作成して、headタグをrenderに置き換える。

application.html.erb
<%= render 'layouts/rails_default' %>

##Sassとアセットパイプライン

実はアセットパイプラインは最近Railsに追加された機能。

Rails開発者の視点からは、

  • アセットディレクトリ
  • マニフェストファイル
  • プリプロセッサエンジン

この三つの主要な機能が理解の対象となる。

###アセットディレクトリ

Railsのアセットパイプラインでは、静的ファイルを目的別に三つのディレクトリに分類する。

  • app/assets 現在のアプリケーション固有のアセット
  • lib/assets 自分の開発チームによって作成されたライブラリ用のアセット
  • vendor/assets サードパーティのアセット

これらのディレクトリには、それぞれのアセットクラス用のサブディレクトリがある。
app/assetの場合

$ ls app/assets
config  images  javascripts  stylesheets

このようなサブディレクトリがある。
つまり、custom.scssはサンプルアプリケーション固有のアセットなので、上記の場所に配置されているということ。

###マニフェストファイル

それぞれのアセットファイルをどのように1つにまとめるのかをRailsに指示するファイルのこと。
実際にアセットをまとめる処理を行うのはSprocketsと言うgem。

ちなみに、マニフェストファイルはCSSとJavaScriptには適用されるが、画像ファイルには適用されない
一つの具体例がコレ。

アプリケーション固有のCSS用マニフェストファイル

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, or any plugin's
 * vendor/assets/stylesheets directory 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 bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 */

CSSコメントの最後の方に注目。

application.css
*= require_tree .
*= require_self
*/

この部分は、Sprocketsgが適切なファイルを読み込むために使われる。

*= require_tree .app/assets/stylesheetsディレクトリ内の全てのCSSファイルが、アプリケーションCSSに含まれるようにしている。

*= require_selfはCSS読み込みシーケンスの中で、application.css自身もその対象に含まれている。

Railsには実用的なデフォルトのマニフェストファイルが付属している。

###プリプロセッサエンジン

必要なアセットをディレクトリに配置してまとめたあとは、
プリプロセッサエンジンを介してブラウザに配信できるようにそれらをマニフェストファイルを用いて統合し、サイトテンプレート用に準備する。

Railsではどのプリプロセッサを使うのか、ファイルの拡張子で判断する。

  • .scss
  • .coffee
  • .erb

の三つが一般的な拡張子である。

プリプロセッサエンジンではメソッドチェーンが使える為、繋げて実行することができる

foobar.js.erb.coffee

この拡張子だと、erbとcoffee両方のプロセッサ経由で実行される。
なお、コードは右から左に実行されるので、coffee→erbという実行手順となる。

###本番環境での効率性

Asset Pipelineの最大のメリットは開発環境と本番環境それぞれで最高の環境が用意できることである。

具体的には、開発環境ではCSSやJavaScriptを個別のファイルで用意し、本番環境ではAsset PipelineでそれぞれのCSSファイルを1つのCSSファイルapplication.cssにまとめ、全てのJavaScriptファイルを一つのJSファイルjavascripts.jsにまとめる。

さらに、それら全てのファイルのインデントや空白を取り除く処理を行い、ファイルを最小化する。

Asset Pipelineの結果、ユーザーから見て素早い動きでありながら開発環境ではプログラマに取って書きやすい形態を取ることができる。

###Sass

SassはCSSに拡張的な機能の付いた言語。
Sassが提供する二つの重要な機能に、ネスト変数がある。

SassはSCSSというフォーマットに対応している。すなわち、.scssという拡張子はSCSSである。
CSSファイルはSCSSファイルとしても扱うことができるため、互換性のあるフォーマットになっている。
(RailsTutorialではBootstrapの恩恵を得る為に最初からSCSSを使っている)

Railsのアセットパイプラインは.scssという拡張子を持つファイルをSassを使って自動的に処理してくれる。

つまり、custom.scssファイルはSassプリプロセッサによって前処理され、その後ブラウザへの配信に備えてパッケージ化される。

####ネスト

要素を入れ子構造にすることである。

従来のCSSでは

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

このように分けて書いていた物を

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

このように書ける。
ネストの内側にあるh1は、.centerのルールを継承しているという点に注目。

属性もネストできる。

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

このように分けていたhover属性を

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

%(アンパーサンド)でネストできる。
こうするとSassがSCSSをCSS変換するときに&:hoverを'#logo:hover`に置き換えている。

今度はfooterのCSSをSCSSを用いてネスト構造にしてみる。

custom.scss
footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid #eaeaea;
  color: #777;
  a {
  color: #555;
    &:hover {
    color: #222;
    }
  }
  smail {
    float: left;
  }
  ul {
    float: right;
    list-style: none;
    li {
    float: left;
    margin-left: 15px;
    }
  }
}

CSSが適切に動作していればOK.

####変数

Sassではなんと変数が定義できる(これは便利や)

例えばこちらの冗長なコード。

h2 {
 color: #777;
}

footer {
 color: #777;
}

同じプロパティの値が設定されている。
Sassでは、このような値#777を変数として定義し、変数名を与えることができる。

$light-gray: #777;

これを使ってSCSSを次のように書き直すことができる。

custom.scss
$ligth-gray: #777;

h2 {
 color: $light-gray;
}

footer {
 color: $ligth-gray;
}

パッと見面倒臭そうだが、#777と記述するより`$light-gray'の方が色がわかりやすい(灰色)ので、変数名を与えること有用である。
(Bootstrapフレームワークでは、多くの色に対して変数名が定義されている)

定義されている変数はLESS変数一覧
で参照できる。

また、bootstrap-sassというgemを使えば、Sassでも同様の変数が使える。

LESSとSassの違いとして、@マークが$マークに変わっていることなどが挙げられる。

@gray-light: #777;  #LESS
$gray-light: #777;  #Sass

用意されている変数($gray-lightなど)をSCSSで
使うには、bootstrap-sassというgemを使う。

custom.scss
h2 {
 color: $gray-light;
}

footer {
 color: $gray-light;
}

実際にネストや変数を使ってcustom.scssを書き直してみる

custom.scss
@import "bootstrap-sprockets";
@import "bootstrap";

/* mixins, variables, etc. */

$gray-medium-light: #eaeaea;

/* universal */

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: $gray-light;
}

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;
  &:hover {
    color: white;
    text-decoration: none;
  }
}

/* footer */

footer {
  margin-top: 45px;
  padding-top: 5px;
  border-top: 1px solid $gray-medium-light;
  color: $gray-light;
  a {
    color: $gray;
    &:hover {
      color: $gray-darker;
    }
  }
  small {
    float: left;
  }
  ul {
    float: right;
    list-style: none;
    li {
      float: left;
      margin-left: 15px;
    }
  }
}

##レイアウトのリンク

footerパーシャルのレイアウトリンクを弄ってみる。
元々HTML記法の<a href="/static_pages/about">About</a>が使われていたが、これはRails流ではないので以下のようにlink_toメソッドで記述する。

_footer.html.erb
<li><%= link_to "About",  about_path %></li>

about_pathとは、名前付きルートと呼ばれるもので、これはルーティングで設定するが、後ほど解説する。

###Contactページ

まずはContactページを弄っていく。とりあえずテストから。

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

テストはRED

Contactページへのルートを追加。

routes.rb
  get 'static_pages/contact'

さらにアクションを追加。

static_pages_controller.rb
  def contact
    
  end

ビューも追加。

contact.html.erb
<% provide(:title, "Contact") %>    
    <h1>Contact</h1>
    <p>
    お問い合わせはこちら
    </p>

再度テストしてGREENならOK。

$ rails t

###RailsのルートURL

現在のhomeのルーティングは

routes.rb
  root 'static_pages#home'

rootメソッドを使って、ルートURLをコントローラのアクションに紐付けている。
このようなルーティングを定義することは、ブラウザからアクセスしやすくすることだけでなく、名前付きルートを使ってURLを参照することができるようになる。

ルートURLにはroot_pathroot_urlといったメソッドを通してURLを参照できる。

Railsチュートリアルでは基本的にroot_path書式を使う。
リダイレクトの場合のみroot_url書式を使う。(HTTPの標準としてリダイレクト時に完全なURLが要求される為)

ここでデフォルトのルーティングを名前付きルートに変更する。
例えば、

get `static_pages/help`

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

という書き方に変更する。

このコードの意味は GETリクエストが/helpに送信されたときにStaticPagesコントローラのhelpアクションを呼び出す。
また、ルートURLの時と同様にhelp_pathhelp_urlといった名前付きルートも使えるようになる。

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

このように考えて、ルーティングを変更してみる。

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を使って行く。

ルーティングを変更したのでテストもroot_pathに変更する。

static_pages_controller_test.rb
  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

テストを走らせてGREENであれば成功。

$ rails t
4 tests, 8 assertions, 0 failures, 0 errors, 0 skips

ここで演習をやってみる。

1:helpルーティングにas:オプションで名前付きルートをhelfに変更してみる。

routes.rb
  get '/help', to: 'static_pages#help', as: 'helf'

2:この状態でtestを走らせると、REDになることを確認。

$ rails t
4 tests, 6 assertions, 0 failures, 1 errors, 0 skips

テストを修正しGREENに。

static_pages_controllers_test.rb
  test "should get help" do
    get helf_path
$ rails t
4 tests, 8 assertions, 0 failures, 0 errors, 0 skips

3:エディタのUndo機能を使って元に戻す

コマンドで戻せばOK

###名前付きルート

ルーティングでルートURLを定義したことにより、レイアウト内で名前付きルートが使えるようになった
実際にlink_toメソッドで使ってみる。2番目の引数をいじる。

_header.html.erb
    <%= 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>

footerパーシャルもリンクを変更。

_footer.html.erb
      <li><%= link_to "About",  about_path %></li>
      <li><%= link_to "Contact",  contact_path %></li>

実際にクリックしてリンクに飛べるか確認。

演習

1:helfルーティングを作成し、レイアウトのリンクを更新してみる。

2:Undo機能で元に戻す

###リンクのテスト

先ほど貼ったリンクをテストする。
今回は今までの単体テストとは違い、統合テストを行う。

まずはテスト用のテンプレートを生成。

$ rails g integration_test site_layout
Running via Spring preloader in process 4732
      invoke  test_unit
      create    test/integration/site_layout_test.rb

ここで、integration_testと言うのは統合テストのことである点に注目。
その後ろにsite_layoutというテンプレートを生成している。

今回のテストの目的は、アプリケーションのHTML構造を調べて、レイアウトの各リンクが正しく動くかどうかチェックすること

- ルートURL(Homeページ)にGETリクエストを送る。
- 正しいページテンプレートが描画されているかどうか確かめる。
- Home,Help,About,Contactの各ページへのリンクが正しく動くか確かめる。

Railsの統合テストでは、上の三つのステップをコードに落とし込んで行く
これを確認するために、assert_templateメソッドを使ってHomeページが正しいビューを描画しているかどうか確かめる。

site_layout_test.rb
require 'test_helper'

class SiteLayoutTest < ActionDispatch::IntegrationTest
  # test "the truth" do
  #   assert true
  # end
  
  test "layout links" do
    get root_path
    assert_template 'static_pages/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メソッドの高度なオプションを使っている。

assert_select "a[href=?]", about_path

このコードでは、?部分を自動的にabout_pathに置換している。
この時、about_path内に特殊記号があればエスケープ処理される。

これにより、次のようなHTMLがあるかどうかをチェックすることができる。

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

そして、ルートURLへのリンクは二つあるので、root_pathへの確認では

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

count: 2で二つのカウントを取る(Homeページのリンクの個数を調べる)

assert_selectには様々な指定方法がある。
ここでは、頻繁に使われる一部のコードを紹介する。

Code	マッチするHTML
assert_select "div"	<div>foobar</div>
assert_select "div", "foobar"	<div>foobar</div>
assert_select "div.nav"	<div class="nav">foobar</div>
assert_select "div#profile"	<div id="profile">foobar</div>
assert_select "div[name=yo]"	<div name="yo">hey</div>
assert_select "a[href=?]", ’/’, count: 1	<a href="/">foo</a>
assert_select "a[href=?]", ’/’, text: "foo"	<a href="/">foo</a>
表 5.2: assert_selectのいくつかの使用例

統合テストを実行するには次のようなRakeタスクを実行する

$ rails test:integration
1 tests, 5 assertions, 0 failures, 0 errors, 0 skips

つまり、`integration'ディレクトリ下のテストファイルの検証を行い、5アサーションが通りましたよという意味。

今度は全てのテストを走らせて、GREENになるかどうか確かめる。

$ rails t
5 tests, 13 assertions, 0 failures, 0 errors, 0 skips

5つのテストを検証し、13個のアサーションが通った模様。

演習

1:footerパーシャルのabout_pathcontact_pathに変更し、テストが正しくエラーを捕まえるか確認。

5 tests, 12 assertions, 1 failures, 0 errors, 0 skips

2:Applicationヘルパーで使っているfull_titleヘルパーをtest環境でも使えるようにする。

とりあえずtest_helper.rbに以下を追記

test_helper.rb
class ActiveSupport::TestCase
 fixtures :all
 include ApplicationHelper

test環境でもアプリケーションヘルパーを使えるようにした。

site_layout_test.rb
    get contact_path
    assert_select "title", full_title("Contact")

test環境でfull_titleヘルパーを使う。

さらに、Applicationヘルパーをテストするファイルを作成する

require 'test_helper'

class ApplicationHelperTest < ActionView::TestCase
  test "full title helper" do
    assert_equal full_title,        "Ruby on Rails Tutorial Sample App"
    assert_equal full_title("Help"),"Help | Ruby on Rails Tutorial Sample App"
  end
end

こうすることでbase_titleの誤字を発見できるようになる。
assert_equalでfull_titleと""の文字列が正しいかどうか検証している。

testを走らせる。

$ rails t
1 tests, 2 assertions, 0 failures, 0 errors, 0 skips

##ユーザー登録

ここからユーザー登録機能を設計する為のコントローラを作成する。

 $ rails g controller Users new
Running via Spring preloader in process 9035
      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

Usersコントローラは新規ユーザー作成のコントローラ、という意味である。(RESTアーキテクチャの規約に従う)
さらに、初期設定でnewアクションを追加しておく。
この時、スタブのユーザービューも作成されている。

作成されたのを確認したら、とりあえずテストを走らせてみる。

$ rails t
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

OK。

演習

1:getレスポンスをsignup_pathに変更

users_controllers_test.rb
    get signup_path

2:テストがREDになったのを確認。

$ rails t
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips

これは後signup_pathを作成するので今はOK。

###ユーザー登録用URL

ここで、先ほど設定したsignup_pathが通るように、ルーティングに/signupを設定する。

routes.rb
  get '/signup',  to: 'users#new'

これでテストを走らせる。

$ rails t
1 tests, 6 assertions, 0 failures, 0 errors, 0 skips

OK。

あとはhomeぺージにsignupへのリンクを名前付きルートで貼る。

home.html.erb
  <%= link_to "Sign up now!", signup_path, class: "btn btn-lg btn-primary" %>

あとはsignupページ用のカスタムスタブのビューに以下を追加。

new.html.erb
<% provide(:title, 'Sign up') %>
<h1>新規登録</h1>
<p>ユーザー登録はこちらからできまっせ〜</p>

このビューはルーティングで指定している通り、signup_pathのビューなので注意。

あとはrails sでSing up nowボタンをクリックしてsignupに飛べるか確認してみる。

演習

1:動作確認済み

2:signupルートをコメントアウトしてテストがREDになるか確認
*signup_pathを取得できないのでREDになる

3:統合テストにsignupページにアクセスするコードを追加

site_layout_test.rb
get signup_path
assert_select "title", full_title("Sign up")

テストを走らせる。

$ rails test:integration
1 tests, 7 assertions, 0 failures, 0 errors, 0 skips

OK。

##Git Heroku

いつも通りGitを使う。masterブランチにマージ。

$ git add -A
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout

テストを走らせる。

$ rails t
7 tests, 18 assertions, 0 failures, 0 errors, 0 skips

問題なければBitbucketにプッシュ。Herokuへデプロイ

$ git push
$ git push heroku

ここでherokuの本番環境で起動しなかった為、マイグレーションを起動させてみる。

heroku run rake db:migrate

これでOK。

第6章へ

#単語集

  • Bootstrap

Twitter社が開発したオープンソースのWebデザインフレームワーク。
Webデザインを効率よく書けるツールで、フロントエンド周りのコーティングが苦手なエンジニアでも整ったページが作れる。

  • class

CSSでスタイルを指定する時の印。classはHTMLページで何度でも使える。

  • id

一部分にスタイルを指定したい場合に付ける印。idはHTMLページで一度しか使えない。

  • image_tag

イメージタグを生成する。
書き方

image_tag(画像ファイルへのパス,[,(オプション or HTMLオプション)])
  • alt

画像が表示されない場合にこの部分が表示される。
また、視覚障害者が使うスクリーンリーダーでは、この属性が読み上げられ、そこに画像があることが示される。

  • link_to

Railsのリンクメソッド。
書き方

link_to ("画像ディレクトリの場所","画像クリック時のURL")
  • レスポンシブデザイン

スマホでもタブレットでもPCでもWebページが綺麗に閲覧できることを目指したWebデザイン手法。

  • タイポグラフィ

テキストや画像の配置を整える技法のこと。Webデザインには必須。

  • em

文字のサイズを1とする単位のこと。

  • shim

既存のコードの動作を修正する為に使用されるコード。

  • render

指定したRHTMLを返す。Railsヘルパーの呼び出しに使う。
書き方

<%= render '相対パス' %>
  • アセットパイプライン

CSS,JavaScript,画像などを一まとまりとして考え、生産性と管理を大幅に強化する機能。

  • CoffeeScript

プログラミング言語。書いたコードがJavaScriptのコードに変換されるが、JavaScriptより簡単に書けるのが特徴。

  • root_path

名前付きルートのメソッドで、ルートURL以下の文字列を返す

root_path -> '/'
  • root_url

名前付きルートのメソッドで、完全なURLの文字列を返す

root_url -> 'http://www.example.com/'
  • as

名前付きルートを変更するオプション。
as: 変更するルート名で使うことができる

  • 統合テスト

システム開発に置けるプログラムの検証作業の中でも、手続きや関数と行った個々の機能を統合させ、
うまく連携・動作しているかを確認するテストのこと。

統合テストで確認される点

- 個々の機能を果たす為のプログラムモジュールを組み合わせて、データの受け渡しがうまく行われているか
- コードの記述様式は揃っているか
- データを授受するタイミングはずれていないか
  • Rakeタスク

Rubyで処理内容を定義できるビルドツールのこと。

  • assert_equal

expected == actualがtrueであるかどうかを確かめるアサーション。

  • スタブ

下位モジュールができるまでに使われる代用品のこと(要はテスト用の代役である)

13
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?