Ruby on Rails チュートリアル
-
第3版 目次
- 第1章 ゼロからデプロイまで
- 第2章 Toyアプリケーション
- 第3章 ほぼ静的なページの作成
- 第4章 Rails風味のRuby
- 第5章 レイアウトを作成する
- 第6章 ユーザーのモデルを作成する
- 第7章 ユーザー登録
- 第8章 ログイン、ログアウト
- 第9章 ユーザーの更新・表示・削除
- 第10章 アカウント有効化とパスワード再設定
- 第11章 ユーザーのマイクロポスト
- 第12章 ユーザーをフォローする
|
||
第3版 目次
|
||
最新版を読む |
Ruby on Rails チュートリアル
プロダクト開発の0→1を学ぼう
下記フォームからメールアドレスを入力していただくと、招待リンクが記載されたメールが届きます。リンクをクリックし、アカウントを有効化した時点から『30分間』解説動画のお試し視聴ができます。
メール内のリンクから視聴を開始できます。
第3版 目次
- 第1章 ゼロからデプロイまで
- 第2章 Toyアプリケーション
- 第3章 ほぼ静的なページの作成
- 第4章 Rails風味のRuby
- 第5章 レイアウトを作成する
- 第6章 ユーザーのモデルを作成する
- 第7章 ユーザー登録
- 第8章 ログイン、ログアウト
- 第9章 ユーザーの更新・表示・削除
- 第10章 アカウント有効化とパスワード再設定
- 第11章 ユーザーのマイクロポスト
- 第12章 ユーザーをフォローする
第5章 レイアウトを作成する
第4章の簡単なRubyツアーの中で、サンプルアプリケーション (4.1) にアプリケーションスタイルシートを含める方法を学びました。しかし、4.3.4で指摘したとおり、このスタイルシートは空のままです。この章では、アプリケーションにBootstrapフレームワークを組み込み、そして、カスタムスタイルを追加します1。また、これまで作成したページ (HomeやAboutなど) へのリンクをレイアウトに追加します (5.1)。その途中で、パーシャル、Railsのルーティング、Asset Pipelineについて学び、さらにSassについても紹介します(5.2)。章の最後に、ユーザーをサイトにログインさせるための重要な一歩を踏み出します (5.4)。
本章では、サンプルアプリケーションにレイアウトを追加したり、修正したりといった部分に注力していきます。また、レイアウトについてはテスト駆動開発で進めたり、全くテストを書かない箇所もでてきます。テストを書くときと書かないときのガイドラインについては、コラム3.3で解説します。この結果、本章ではテキストエディタによる修正とブラウザによる確認がほとんどになります。テスト駆動開発で進める唯一の箇所は、5.3.1のContactページの追加する箇所のみです。最後に、新しいテスト手法「 統合テスト (Integration Test)」について紹介します (5.3.4)。統合テストを使って、最終的なレイアウトやリンクが正しいかどうかをチェックします。
5.1 構造を追加する
RailsチュートリアルはWeb開発のための本であり、Webデザインの本ではありませんが、だからといって何のスタイルもない寒々しい外観のアプリケーションでいつまでも作業を続けていると憂鬱になってしまいます。そこで、この章ではレイアウトにいくつかの構造とCSSを与えて最小限のスタイルを追加します。カスタムCSSルールの他に、Twitter社によるオープンソースのWebデザインフレームワークであるBootstrapを利用します。また、コードそのものにもスタイルを与えます。つまり、散らかりはじめたコードレイアウトをパーシャルを使用して整えるということです。
Webアプリケーションを作成するときに、ユーザーインターフェイスの概要をできるだけ早いうちに把握しておくことがしばしば有用です。本書の残りでは、モックアップ (Webの文脈ではよく ワイヤーフレームと呼ばれます) という、最終的なアプリケーションの外観を示す一種のラフスケッチを使用することにします2。この章では、 主に3.2で紹介したサイトロゴ、ナビゲーションヘッダー、サイトフッターを含む静的ページを開発します。これらのページの中で最も重要な、Homeページのモックアップを図5.1に示します。モックアップに基いて作成した最終結果は図5.7で確認することができます。両者を見比べると、細部が若干異なることに気が付くでしょう (たとえば、実際には最後にRailsのロゴをページに追加します)。しかしモックアップは正確である必要はありませんので、これで十分です。
Gitでバージョン管理をしているのであれば、これまでと同様、この時点で新しいブランチを作成するのがよいでしょう。
$ git checkout master
$ git checkout -b filling-in-layout
5.1.1 ナビゲーション
第一段階として、サンプルアプリケーションにリンクとスタイルを追加するために、サイトのレイアウトファイルapplication.html.erb
(リスト4.3で登場) にHTML構造を追加し、レイアウトファイルを更新します。この更新には、領域 (divタグ) の追加、CSSクラスの追加、サイトナビゲーションの起点となる領域の追加も含まれます。完全なファイルをリスト5.1に示します。続いて、これを構成している多くの部品について解説します。表示結果を今すぐ確認したいのであれば、図5.2で確認できます(注:この時点ではわざわざ見に行くほどの仕上がりではありませんが)。
<!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="//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>
それでは、リスト5.1の新しい要素を上から順に見ていきましょう。3.4.1でも簡単に説明しましたが、RailsはデフォルトでHTML5を使用します (<!DOCTYPE html>
というdoctypeでそのことが示されています)。HTML5は比較的新しく、一部のブラウザ (特に旧式のInternet Explorer) ではHTML5のサポートが不完全であるため、以下のようなJavaScriptコード (通称 “HTML5 shim”)3 を使用してこの問題を回避します。
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
上のコードには、以下のような奇妙な構文が含まれています。
<!--[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をインクルードすることができるため、非常に好都合です。
それに続くセクションには、サイトのロゴを表示するheader
、(div
タグによる) いくつかの領域、ナビゲーションリンクのリストがあります。
<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
タグは、ページのトップに来るべき要素を表します。このheader
タグには、navbar
、navbar-fixed-top
、navbar-inverse
という3つのCSSクラス3がスペース区切りで与えられています。
<header class="navbar navbar-fixed-top navbar-inverse">
すべてのHTML要素には、クラスとidの両方を指定することができます。これらは単なるラベルで、CSSでスタイルを指定するときに便利です (5.1.2)。クラスとIDの主な違いは、クラスはページの中で何度でも使用できるのに対し、IDは一度しか使用することができない点です。今回の場合、すべてのnavbarクラスには、5.1.2でインストールするBootstrapフレームワークによって特別な意味が与えられます。
header
タグの内側には2つのdiv
タグがあります。
<div class="container">
div
タグは一般的な表示領域を表し、ドキュメントを別々のパーツに分ける以外のことはしません。古いスタイルのHTMLでは、div
タグはサイトのほぼすべての領域に使用されますが、HTML5では多くのアプリケーションに共通の領域で使用するheader
要素、nav
要素、section
要素が追加されています。この場合、div
タグにもCSSクラス (container
) が与えられています。header
タグのクラスと同様に、このクラスもBootstrapにおいて特別な意味を持っています。
divに続いて、埋め込みRubyコードが出現します。
<%= 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>
ここでは、リンク (3.3.2で、アンカータグa
を使用して作成) を生成するために、Railsヘルパーのlink_to
を使用しています。link_to
の第1引数はリンクテキスト、第2引数はURLです。このURIは5.3.3で名前付きルートのURLに変更しますが、今はWebデザインで一般に使用されるスタブURI’#’
にしておきます。第3引数はオプションハッシュで、この場合はサンプルアプリのリンクでCSSのid logo
を指定しています(他の3つのリンクにはオプションハッシュが指定されていませんが、必須ではないので構いません)。Railsヘルパーは、このようにオプションのハッシュを取ることがよくあり、これによりRailsのコードから離れることなく任意のHTMLオプションを柔軟に追加することができます。
divの内側の2番目の要素は、リストアイテムタグli
と順不同リストタグul
によって作られた、ナビゲーションリンクのリストです。
<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>
正確にはここでは不要なのですが、nav
タグには「その内側がナビゲーションリンクである」という意図を明示的に伝える役割があります。さらに、ul
タグに付与されているnav
やnavbar-nav
、navbar-right
クラスもBootstrapにおいて特別な意味を持ちます。したがって、5.1.2でBootstrapのCSSを追加したときに、これらのスタイルも自動的に適用されます。ブラウザからソースを見ることで確認ができますが、Railsが埋め込みRubyを評価し、レイアウトを描画すると、上のリストは以下のように置き換わります5。
<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>
これがブラウザに返されるHTMLになります。
レイアウトの最後の部分は、メインコンテンツ用のdiv
です。
<div class="container">
<%= yield %>
</div>
上と同様、container
クラスもBootstrapにおいて特別な意味を持ちます。3.4.3で学んだように、yield
メソッドはWebサイトのレイアウトにページごとの内容を挿入します。
5.1.3で追加するサイトフッターを除いて、これでレイアウトは完成しました。Homeページへアクセスして表示結果を確認することができます。今後登場するスタイル要素を利用できるようにするために、home.html.erb
ビューに特別な要素をいくつか追加します(リスト5.2)。
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="http://www.railstutorial.org/">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/' %>
第7章でサイトにユーザーを追加するときに備えて、最初のlink_to
に仮のリンクを作成します。
<a href="#" class="btn btn-lg btn-primary">Sign up now!</a>
上で挙げたdiv
タグのCSSクラスjumbotron
や、signupボタンのbtn
クラス、btn-lg
クラス、btn-primary
クラスはすべて、Bootstrapにおいて特別な意味を持ちます。
2番目のlink_to
では、引数として画像ファイルのパスと任意のオプションハッシュをとるimage_tag
ヘルパーの能力が示されています。シンボルを使用して、この場合はalt
属性を設定しています。画像を表示するためには、rails.png
というRailsのロゴ画像ファイルを加える必要があります。Ruby on Rails公式ページの http://railstutorial.jp/rails.png から画像をダウンロードして、app/assets/images/
ディレクトリに置いてください。Cloud IDEやUnix系のOS (Max OS Xなど) を使っている場合は、次のようにcurl
コマンドで簡単に取得できます6。
$ curl -OL http://railstutorial.jp/rails.png
$ mv rails.png app/assets/images/
Cloud IDEを使っていると、(筆者にも理由は分からないのですが) ときどき2行目のmvコマンドで失敗することがあるようです。その場合は、1行目のcurl
コマンドをもう一度実行して、ロゴ画像が正しくダウンロードできているかどうか確認してください (curl
コマンドの詳細については、Conquering the Command Lineという本の第3章 (英語) を参照してください) 。リスト5.2でimage_tag
ヘルパーを使っているので、Railsは該当する画像ファイルを、アセットパイプラインを通してapp/assets/images/
ディレクトリの中から探してくれます (アセットパイプラインについては5.2で説明します)。
image_tag
の効果を確かめるために、ブラウザから生成されたHTMLを見てみましょう7。
<img alt="Rails logo" src="/assets/rails-9308b8f92fea4c19a3a0d8385b494526.png" />
ファイル名が重ならないようにするために、Railsが9308b8f92fea4c19a3a0d8385b494526
という文字列 (実際の文字列はシステムごとに異なります) を追加していることがわかります。これは、たとえば画像ファイルを新しい画像に更新したときに、ブラウザ内に保存されたキャッシュに意図的にヒットさせないようにするための仕組みです。また、src
属性には "images
" というディレクトリ名が含まれていないことにも注目してください。これはassets
ディレクトリ内の他のディレクトリ (imagesやjavascripts、stylesheetsなど) も同様です。これは高速化のための仕組みで、Railsはassets
ディレクトリ直下の画像をapp/assets/images
ディレクトリにある画像と紐付けています。これにより、ブラウザから見るとすべてのファイルが同じディレクトリにあるように見えるようになります。そして、このようなフラットなディレクトリ構成を採っていると、ファイルをより高速にブラウザに渡すことができるようになります。最後に、alt
属性は、画像がない場合に代わりに表示される文字列です。たとえば視覚障害のあるユーザーが使用するスクリーンリーダーでは、ここの属性が読み上げられて、そこに画像があることが示されます。
いよいよ、ここまでの苦労の成果を確認する準備ができました (図5.2)。思っていたよりもみすぼらしいでしょうか。そうかもしれません。しかし、HTML要素に実用的なクラスを与えるという良い仕事ができたのも確かです。さらに、クラスを与えたこの段階で、CSSを使用してサイトにスタイルを与えることができたのは、タイミングとして非常に適切であると思います。
5.1.2 BootstrapとカスタムCSS
5.1.1では、多くのHTML要素にCSSクラスを関連付けました。こうしておくことで、CSSベースでレイアウトを構成する際に高い柔軟性を与えてくれます。5.1.1で述べたように、これらのクラスの多くは、Twitterが作成したフレームワークであるBootstrap特有のものです。Bootstrapを使用すると、洗練されたWebデザインとユーザーインターフェイス要素を簡単にHTML5アプリケーションに追加することができます。この節では、サンプルアプリケーションにスタイルを追加するために、カスタムCSSルールとBootstrapを組み合わせて使用します。注目すべき点は、Bootstrapを使うことでアプリケーションをレシポンシブデザインにできるということです。これにより、どの端末でアプリケーションを閲覧しても、ある程度見栄えをよくすることができます。
最初に、リスト5.3で示しているようにBootstrapを追加しましょう。これは、bootstrap-sass gemを使用してRailsアプリケーションに導入できます。Bootstrapフレームワークでは、動的なスタイルシートを生成するためにLESS CSS言語を使用していますが、RailsのAsset Pipelineはデフォルトでは (LESSと非常によく似た) Sass言語をサポートします (5.2)。そのため、bootstrap-sassは、LESSをSassへ変換し、必要なBootstrapファイルを現在のアプリケーションですべて利用できるようにします8。
Gemfile
へbootstrap-sassを追加する
source 'https://rubygems.org'
gem 'rails', '4.2.2'
gem 'bootstrap-sass', '3.2.0.0'
.
.
.
いつものようにbundle install
を実行して、Bootstrapをインストールします。
$ bundle install
ちなみに、rails generate
コマンドを実行することでコントローラーごとに分けられたCSSファイルが自動的に生成されますが、これらのファイルを正しい順序で読み込ませるのは至難の技なので、本チュートリアルでは (簡潔のために) すべてのCSSを1つにまとめる方針を採っています。カスタムCSSを動かすための最初の一歩は、カスタムCSSファイルを作ることです。
$ touch app/assets/stylesheets/custom.css.scss
(ここでは3.3.3の途中で紹介したtouch
コマンドを使っていますが、ファイルが作成できるなら [新規ファイル作成] や他のコマンドでも問題ありません。) このディレクトリ名とファイル名は、どちらも重要です。以下のディレクトリは、
app/assets/stylesheets/
Asset Pipeline (5.2)の一部であり、このディレクトリに置かれたスタイルシートはapplication.css
の一部として自動的にWebサイトのレイアウトにインクルードされます。さらに、ファイル名のcustom.css.scss
には.css
という拡張子も含まれているので、このファイルはCSSファイルであることが示されています。また、.scss
という拡張子も含まれているので、 このファイルはSassを記述できるCSSファイル (Sassy CSS: Scss) であることも示されており、Asset Pipelineはこれを見てSassを処理できるようにします(Sassは5.2.2まで登場しませんが、bootstrap-sass gemが動作するためのおまじないとして必要です)。
カスタムCSS用のファイルを作成したら、リスト5.4のように@import
を使用して、Bootstrap (とそれに関連するSprockets) をインクルードします9。
@import "bootstrap-sprockets";
@import "bootstrap";
リスト5.4の2行では、Bootstrap CSSのフレームワークを導入しています。導入後、Webサーバを再起動させると、アプリケーションに反映させることができます (1.3.2で紹介したように、Ctrl-Cを押してWebサーバを停止させた後、rails server
コマンドを打ってWebサーバを起動してください)。うまくいけば図5.3のような結果になります。さて、テキストの配置は今ひとつで、ロゴにはスタイルもありませんが、色使いとsignupボタンはなかなかよい感じになってきました。
次に、リスト5.5に示したように、Webサイト全体にわたってレイアウトと個別のページにスタイルを与えるためのCSSを追加します。テストの結果を図5.4に示します。リスト5.5には多数の記述ルールがあります。CSSの記述ルールを把握するためには、関心のある箇所をコメントアウトして表示を確認することをお勧めします。CSSでは、/* … */
でコメントアウトできるので、調べてみたいコードをこれで囲い、表示がどのように変わるかを確認してみてください。
@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;
}
リスト5.5のCSSの形式は一貫しています。CSSルールでは一般に、クラス、id、HTMLタグ、またはそれらの組み合わせ、のいずれかを指定します。そしてその後ろにスタイリングコマンドのリストを記述します。たとえば、以下のコードでは、
body {
padding-top: 60px;
}
ページ上部に60ピクセルの余白を追加します。header
タグにnavbar-fixed-top
クラスが与えられているので、これに従ってBootstrapはナビゲーションバーをページ上部に固定し、ナビゲーションバーの下に余白を置いて主要部分から分離します(デフォルトのnavbarの色がBootstrap 2.0から変更されたため、現在の淡色の代わりにダークな色調にしたい場合はnavbar-inverse
クラスを使用する必要があります)。また、このルールにある以下のCSSは、
.center {
text-align: center;
}
center
クラスにtext-align: center
プロパティを関連付けています。言い換えると、.center
冒頭のドット.
は、このルールがクラスに対してスタイルを適用することを示しています。(冒頭がポンド記号#
の場合は、リスト5.7に示したように、そのルールがCSSのidに対してスタイルを適用することを示します。この場合、center
クラスに属している (div
などの) タグの内側にある要素は、すべてページ中でセンタリングされることを意味しています(このクラスの例はリスト5.2で参照できます)。
Bootstrapには洗練されたタイポグラフィーを利用できるCSSルールがありますが、ここではさらに、リスト5.6に示したようにサイトのテキストの外観を変えるカスタムCSSルールを追加しましょう。(これらのルールはHomeページですべて適用されるとは限りませんが、サンプルアプリケーションの他の場所でも使用されるものもあります)。リスト5.6を反映した結果を図5.5で確認することができます。
@import "bootstrap-sprockets";
@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: #777;
}
p {
font-size: 1.1em;
line-height: 1.7em;
}
最後に、いくつかのルールをサイトロゴに追加します。このサイトロゴは「sample app」だけが表示されているシンプルなものです。リスト5.7のCSSは、テキストを大文字に変換し、サイズ、色、配置を変更します(サイトロゴがページで一度しか使用されないことを前提としてCSS idを使用していますが、代わりにクラスを使用することもできます)。
@import "bootstrap-sprockets";
@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;
}
#logo:hover {
color: #fff;
text-decoration: none;
}
上のコードのcolor: #fff
は、ロゴの色を白に変更します。HTMLの色は、16進数 (基数が16) の3つの数値の組み合わせで表現され、赤、緑、青の三原色に (この順序で) コード化することができます。このコード#ffffff
は、3色すべてが最大に使用されており、純白になります。なお、#fff
は、完全な#ffffff
の短縮形です。CSS標準には、共通HTMLカラーの別名も多数定義されています。たとえば、#fff
をwhite
と書くこともできます。リスト5.7のCSSの結果は図5.6で確認できます。
5.1.3 パーシャル (partial)
リスト5.1のレイアウトはその目的を果たしていますが、少々散らかっています。HTML shimは、それだけで3行も占有し、風変わりなIE特有の文法を使用しているので、これをうまく隠すことができたらどんなによいでしょう。また、HTMLヘッダーは論理的な単位を形成するため、一箇所にまとめる必要もあります。Railsでは、パーシャル (partial) と呼ばれる機能を使用してこれを実現することができます。最初に、パーシャルを定義するとレイアウトがどのように変わるかを見てみましょう (リスト5.8)。
<!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>
リスト5.8では、以下のようにrender
と呼ばれるRailsヘルパー呼び出しだけを使って、HTML shimのスタイルシート行を置換しています。
<%= render 'layouts/shim' %>
この行では、app/views/layouts/_shim.html.erb
というファイルを探してその内容を評価し、結果をビューに挿入しています10 (<%= ... %>は、テンプレート内でRubyの式を評価するための埋め込みRuby記法であることを思い出してください。評価した結果がテンプレートに挿入されます)。ファイル名_shim.html.erb
の前のアンダースコアに注目してください。このアンダースコアは、パーシャルで使用する普遍的な命名規約であり、また、一目見ただけでディレクトリ中のすべてのパーシャルを識別することが可能になります。
もちろん、パーシャルが動作するためには、それに対応するファイルとコンテンツを記述しなければなりません。このshimパーシャルの場合は、リスト5.1のわずか3行のshimコードだけです。追加した結果をリスト5.9に示します
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/r29/html5.min.js">
</script>
<![endif]-->
同様に、他のヘッダーの情報もリスト5.10のパーシャルに移動し、render
を呼び出してレイアウトに挿入することができます。(パーシャルでは、自動生成せずに、テキストエディタを使って手動で作成するのが一般的です。)
<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.html.erb
で、layoutsディレクトリ (リスト5.11) に置けばよいということがわかると思います11。
<footer class="footer">
<small>
The <a href="http://www.railstutorial.org/">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>
ヘッダーの場合と同様に、フッターの中でもlink_to
メソッドを使用して、AboutページとContactページへの内部リンクを追加してあります。ひとまず、リンク先のURLは’#’
としておきます(header
タグと同様、footer
タグもHTML5で新たに追加された要素です)。
フッタパーシャルは、スタイルシートやヘッダーパーシャルのときと同じ方法でレイアウト中に追加できます (リスト5.12)。
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
そのまま実際にフッターを表示してみるとどうにも見苦しいので、リスト5.13でスタイルを若干追加しましょう。スタイルを追加した結果を図5.7に示します。
.
.
.
/* 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;
}
5.2 SassとAsset Pipeline
最近のRailsに追加された機能の中で最も特筆すべき機能のひとつは、CSS、JavaScript、画像などの静的コンテンツの生産性と管理を大幅に強化する「Asset Pipeline」です。この節では、Asset Pipelineの概要と、素晴らしいCSS生成ツールである「Sass」の使い方について説明します。
5.2.1 Asset Pipeline
アセットパイプラインは、Railsの流儀を守りながら多大な変化をもたらしますが、一般的なRails開発者の視点からは、アセットディレクトリ、マニフェストファイル、プリプロセッサエンジンという、3つの主要な機能が理解の対象となります12。では、それぞれを順に見ていきましょう。
アセットディレクトリ
Rails 3.0以前のバージョンでは、静的ファイルはpublic/
以下の次のディレクトリに置かれていました。
-
public/stylesheets
-
public/javascripts
-
public/images
これらのディレクトリ中のファイルは http://example.com/stylesheets のようなリクエストによって自動的に配信されます。これは3.0以降も同様です。
Rails3.1以降では、静的ファイルを目的別に分類する、標準的な3つのディレクトリが使用されるようになりました。最新のRailsでも同様です。
-
app/assets
: 現在のアプリケーション固有のアセット -
lib/assets
: あなたの開発チームによって作成されたライブラリ用のアセット -
vendor/assets
: サードパーティのアセット
これらのディレクトリには、それぞれのアセットクラス用のサブディレクトリがあります。たとえば、app/assetsには次のようなサブディレクトリがあります。
$ ls app/assets/
images/ javascripts/ stylesheets/
上記の説明から、5.1.2で取り上げたカスタムCSSが配置された場所と、その理由について理解することができると思います。custom.css.scss
は、サンプルアプリケーション固有のアセットなので、app/assets/stylesheets
に配置されているのです。
マニフェストファイル
アセットを上記の論理的な場所へ配置すれば、マニフェストファイルを使用して、それらをどのように1つのファイルにまとめるのかをRailsに指示することができます。なお、実際にまとめるのはSprockets gemが行います。(マニフェストファイルはCSSとJavaScriptには適用されますが、画像ファイルには適用されません) 。1つの例として、アプリケーションスタイルシート用のマニフェストファイルを見てみましょう (リスト5.14)。
/*
* 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 bottom of the compiled file so the styles you add here take
* precedence over styles defined in any styles defined in the other CSS/SCSS
* files in this directory. It is generally better to create a new file per
* style scope.
*
*= require_tree .
*= require_self
*/
上の行で重要な部分は実はCSSコメントの中にあります。以下の行は、適切なファイルをインクルードするためにSprocketsによって使用されます。
/*
.
.
.
*= require_tree .
*= require_self
*/
以下の行は、
*= require_tree .
app/assets/stylesheets
ディレクトリ (サブディレクトリを含む) 中のすべてのCSSファイルが、アプリケーションCSSに含まれるようにします。次の行
*= require_self
CSSの読み込みシーケンスの中で、application.css
自身もインクルードすることを指定しています。
Railsには実用的なデフォルトのマニフェストファイルが付属しているので、Railsチュートリアルでは変更を加える必要がありませんが、もし必要な場合は、Railsガイドの「アセットパイプライン」で詳細な情報を参照できます。
プリプロセッサエンジン
必要なアセットをディレクトリに配置してまとめた後、Railsはさまざまなプリプロセッサエンジンを介してそれらを実行し、ブラウザに配信できるようにそれらをマニフェストファイルを用いて結合し、サイトテンプレート用に準備します。Railsは、どのプリプロセッサを使用するかを、ファイル名の拡張子を使用して判断します。最も一般的な拡張子は、Sass用の.scss
、CoffeeScript用の.coffee
、埋め込みRuby (ERb) 用の.erb
です。3.4.3では最初にERbを、5.2.2ではSassをそれぞれ扱いました。なお本書では扱いませんが、CoffeeScriptはエレガントで簡潔な言語で、JavaScriptにコンパイルして実行します(興味のある方は、RailsCastの「CoffeeScriptの基礎 (英語)」から始めると良いでしょう)。
プリプロセッサエンジンはつなげて実行する (chain) ことができます。
foobar.js.coffee
上の拡張子の場合、CoffeeScriptプロセッサ経由で実行されます。
foobar.js.erb.coffee
上の拡張子の場合は、CoffeeScriptとERbの両方で実行されます (コードは右から左へと実行されますので、この例ではCoffeeScriptが最初に実行されます)。
本番環境での効率性
Asset Pipelineの最大のメリットの1つは、本番のアプリケーションで効率的になるように最適化されたアセットも自動的に生成されることです。従来は、CSSとJavaScriptを整理するために、機能を個別のファイルに分割し、(インデントを多用して) 読みやすいフォーマットに整えていました。これは、プログラマにとっては便利な方法ですが、本番環境にとっては非効率です。それというのも、最小化されていないCSSやJavaScriptファイルを多数インクルードすると、ページの読み込み時間が著しく遅くなるからです (読み込み時間は、ユーザー体験の質に影響を与える重要な指標の1つです)。Asset Pipelineを使うと、この「開発効率と読み込み時間のどちらを重視するか」という問題について悩む必要がなくなります。開発環境ではプログラマにとって読みやすいように整理しておき、本番環境ではAsset Pipelineを使ってファイルを最小化すればよいのです。具体的には、Asset Pipelineがすべてのスタイルシートを1つのCSSファイル (application.css
) にまとめ、すべてのJavaScriptファイルを1つのJSファイル (javascripts.js
) にまとめてくれます。さらに、それらのファイルすべてに対して 不要な空白やインデントを取り除く処理を行い、ファイルサイズを最小化してくれます。結果として、開発環境と本番環境という、2つの異なった状況に対してそれぞれ最高の環境を提供してくれます。
5.2.2 素晴らしい構文を備えたスタイルシート
Sass は、スタイルシートを記述するための言語であり、CSSに比べて多くの点が強化されています。この節では、Sassが提供する2つの重要な機能、ネストと変数について説明します。(3つ目の重要な機能であるミックスインについては、7.1.1で紹介します)。
5.1.2でも簡単に説明しましたが、SassはSCSSというフォーマットに対応しています (.scss
という拡張子はSCSSであることを表します)。SCSSは、厳密な意味で、CSS本体を抽象化したフォーマットです。具体的には、SCSS は CSS に新しい機能を追加しただけで、全く新しい構文を定義したようなものではありません13。本書の例では、Bootstrapの恩恵を得るために、私達は最初からSCSSを使用しています。RailsのAsset Pipelineは、.scss
という拡張子を持つファイルをSassを使って自動的に処理してくれます。このため、custom.css.scss
ファイルはSassプリプロセッサによって前処理され、その後ブラウザへの配信に備えてパッケージ化されます。
ネスト
スタイルシート内に共通のパターンがある場合は、要素をネストさせることができます。たとえば、リスト5.5では、以下のように.center
と.center h1
の両方に対してルールがあります。
.center {
text-align: center;
}
.center h1 {
margin-bottom: 10px;
}
上のルールは、Sassを使用して以下のように書き換えることができます。
.center {
text-align: center;
h1 {
margin-bottom: 10px;
}
}
上の例では、ネストの内側にあるh1
というルールは、.center
のルールを継承しています。
今度は、もう少し異なるルールに対してネスト機能を使う例を見てみましょう。リスト5.7には以下のコードがあります。
#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;
}
上のコードには#logo
というidが2回使用されています。1回目はロゴ自身を定義するために、2回目はhover
属性を定義するために使用されています (なおhover属性は、該当する要素の上にマウスポインタをかざしたときの表示を定義します)。2つ目のルールをネストするためには、親属性である#logo
を参照する必要があります。このような場合、SCSSでは以下のようにアンパーサンド&
を使って実現できます。
#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
に置換します。
これらのネスト機能は、フッターのCSSでも使用できます。リスト5.13のコードは、SCSSを使用して以下のように書き換えることができます。
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;
}
}
}
リスト5.13を手作業で変換してみることは、良い演習になります。変換後にもCSSが適切に動作していることを確認してみましょう。
変数
Sassでは、冗長なコードを削除し、より自由な表現を可能にするために、変数が定義できるようになっています。たとえば、リスト5.6やリスト5.13を見てみると、同じ色を繰り返し参照している箇所があります。
h2 {
.
.
.
color: #777;
}
.
.
.
footer {
.
.
.
color: #777;
}
上のコードの#777
は薄い灰色を指しています。Sassでは、このような値を変数として定義し、以下のように変数名を与えることができます。
$light-gray: #777;
この機能を使用して、SCSSを以下のように書き直すことができます。
$light-gray: #777;
.
.
.
h2 {
.
.
.
color: $light-gray;
}
.
.
.
footer {
.
.
.
color: $light-gray;
}
$light-gray
のような変数名は、#777
のような値よりもわかりやすいので、たとえその変数が繰り返し使われないとしても、変数名を与えることは多くの場合有用です。実際、Bootstrapフレームワークでは、多くの色に対して変数名を定義しています。定義されている変数はBootstrapページの「LESS変数一覧」で参照することができます。このWebサイトでは、SassではなくLESSを使って変数が定義されていますが、bootstrap-sassというgemを使用すれば、Sassでも同様の変数が使えるようになります。LESSとSassの違いを想像するのはそれほど難しくありません。たとえば、LESSではアットマーク@
を使用しているのに対して、Sassはドルマーク$
を使っていることはすぐにわかります。話を戻して、Bootstrapの変数の一覧表を見ると、薄い灰色に対して以下の変数名が与えられることに気が付きます。
@gray-light: #777;
これは、bootstrap-sassというgemを使えば、SCSSでも同様に$gray-light
という変数が使えることを意味しています。先ほど定義した$light-gray
というカスタム変数の代わりに、用意された変数を使ってみましょう。
h2 {
.
.
.
color: $gray-light;
}
.
.
.
footer {
.
.
.
color: $gray-light;
}
今回取り上げたSassのネスト機能や変数機能を使ってSCSSファイルを全面的に書き直すと、リスト5.15のようになります。このリストでは、Sassの変数 (詳しくはBootstrap LESSの変数一覧を参考にしてください) や、組み込みの色変数 (たとえば#fff
にはwhite
という変数) を使っています。footer
タグのルールが、劇的に向上していることを確認してみてください。
@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;
}
}
}
Sassを使ってスタイルシートをより簡単にする方法は他にもありますが、今回はその中でも最も重要な機能を使ってリスト5.16を書き直しました。Sassを使うことによって、素晴らしいスタートを切ることができました。Sassの詳細については、Sass の公式サイト (英語) を参照してください。
5.3 レイアウトのリンク
サイトのレイアウトが美しく仕上がりましたので、今度は’#’
で代用していたリンクを書き換えてみましょう。もちろん、以下のようにリンクを直接記述することもできます。
<a href="/static_pages/about">About</a>
しかし、上の記法はRails流ではありません。まず、aboutページへのURLは/static_pages/aboutよりも/aboutの方がよいでしょう。さらに、Railsでは以下のように名前付きルートを使用するのが慣例となっています。
<%= link_to "About", about_path %>
上のようにすることでコードの意味がわかりやすくなり、about_path
の定義を変えればabout_path
が使用されているすべてのURLを変更できるため、柔軟性が高まります。
今後使用する計画のあるすべてのリンクのリストを、URLとルート (route) のマッピングと共に表5.1に示します。3.4.4で最初のルートは設定済みですが、それ以外のルートについても同様に実装していきます。なお、loginについては本章の最後で少しだけ実装します (第8章で本格的に実装します)。
ページ | URL | 名前付きルート |
Home | / | root_path |
About | /about | about_path |
Help | /help | help_path |
Contact | /contact | contact_path |
Sign up | /signup | signup_path |
Log in | /login | login_path |
5.3.1 Contactページ
まずは、第3章の演習で取り上げたContactページについて追加しましょう。Contactページのテストをリスト5.16に示します。これは単にリスト3.22で使用されているテストのパターンに従ったものです。
require 'test_helper'
class StaticPagesControllerTest < ActionController::TestCase
test "should get home" do
get :home
assert_response :success
assert_select "title", "Ruby on Rails Tutorial Sample App"
end
test "should get help" do
get :help
assert_response :success
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
end
test "should get about" do
get :about
assert_response :success
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
end
test "should get contact" do
get :contact
assert_response :success
assert_select "title", "Contact | Ruby on Rails Tutorial Sample App"
end
end
この時点では、リスト5.16のテストはREDになっているはずです。
$ bundle exec rake test
アプリケーションコードは、3.3のAboutページへの追加と良く似ています。最初にルート (リスト5.18) を更新します。次にcontact
アクションをStaticPagesコントローラ (リスト5.19) に追加します。最後にContactビュー (リスト5.20) を作成します。
Rails.application.routes.draw do
root 'static_pages#home'
get 'static_pages/help'
get 'static_pages/about'
get 'static_pages/contact'
end
class StaticPagesController < ApplicationController
.
.
.
def contact
end
end
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
Contact the Ruby on Rails Tutorial about the sample app at the
<a href="http://www.railstutorial.org/#contact">contact page</a>.
</p>
ここで、すべてのテストがGREENであることを確認しておいてください。
$ bundle exec rake test
5.3.2 Railsのルート
本項では、名前付きルートをサンプルアプリケーションの静的ページで使うために、ルーティング用のファイル (config/routes.rb
) を編集していきます。Railsはこのファイルの内容を見て、URLのマッピングをしています。 まずは、3.4.4で定義したHomeページのルーティングについて見直していきましょう。あのときは特別にHomeページのみ設定をしましたが、残りの静的ページについても同様にルーティングを設定していきます。
私たちはこれまでに、ルートURLを定義するコードを3回見てきました。1つ目は
root 'application#hello'
というHelloアプリケーションのコード (リスト1.10)です。2つ目は
root 'users#index'
というToyアプリケーションのコード (リスト2.3)。そして最後は
root 'static_pages#home'
というSampleアプリケーションのコードです (リスト3.37)。いずれの場合においても、root
メソッドを使ってルートURL "/" をコントローラーのアクションに紐付けていました。ルートURLのようなルーティングを定義することの効果は、ブラウザからアクセスしやすくすることだけではありません。それ以外にも、生のURLではなく、名前付きルートを使ってURLを参照することができるようになります。たとえばルートURLを定義すると、root_path
やroot_url
といったメソッドを通してURLを参照することができます。ちなみに前者はルートURL以下の文字列を、後者は完全なURLの文字列を返します。
root_path -> '/'
root_url -> 'http://www.example.com/'
なお、Railsチュートリアルでは、_path
書式を使用する一般的な規約に従い、リダイレクトの場合のみ_url
書式を使用します。これは、HTTP標準では技術的にリダイレクト後に完全なURLが要求されるためです。ただし、ほとんどのブラウザではどちらの方法でも動作します。
HelpページやAboutページ、Contactページなどの名前付きルートを定義したい場合は、get
ルールを使って定義することができます (リスト5.18)。たとえば次のようなルールは、
get 'static_pages/help'
以下のように書き換えます。
get 'help' => 'static_pages#help'
このようにgetルールを使って変更すると、GETリクエストが /help に送信されたときにStaticPagesコントローラーのhelp
アクションを呼び出してくれるようになります。これにより、/static_pages/help のような冗長なURLが /help のような分かりやすいURLにすることができます。また、ルートURLのときと同様に、help_path
やhelp_url
といった名前付きルートも使えるようになります。
help_path -> '/help'
help_url -> 'http://www.example.com/help'
他の静的ページについても同様にルーティングを変更していくと、リスト5.18はリスト5.22のようなコードになります。
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
end
5.3.3 名前付きルート
リスト5.22でルートを定義したことにより、レイアウトの中で名前付きルートが使えるようになりました。早速、link_to
メソッドの2番目の引数で、適切な名前付きルートを使ってみましょう。たとえば以下のコードの場合、
<%= link_to "About", '#' %>
上を以下のように置き換えます。
<%= link_to "About", about_path %>
他も同様です。
最初に、HomeページとHelpページへのリンクを持つヘッダーパーシャル_header.html.erb
(リスト5.23) から取りかかります。ヘッダーパーシャルでは、Web共通の慣習に従って、ロゴにもHomeページへのリンクを追加します。
<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>
[Log in] リンクの名前付きルートは第8章で作成するため、今の段階では’#’
のままにしておきます。
フッターパーシャル_footer.html.erb
にもリンクがあります。これらはAboutページとContactページへのリンクです (リスト5.24)。
<footer class="footer">
<small>
The <a href="http://www.railstutorial.org/">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>
これで、レイアウトに第3章で作成したすべての静的ページへのリンクができました。たとえば/aboutの場合はAboutページ (図5.8) に移動します。
5.3.4 リンクのテスト
レイアウト内のいくつかのリンクを埋めることができたので、これらのリンクが正しく動いているかどうかチェックするテストを書いてみましょう。ブラウザを立ち上げてルートURLにアクセスし、それぞれのリンクをクリックして確かめることもできますが、変更する度にこの作業を毎回繰り返していくのは大きな負担です。そこで、「統合テスト ((Integration Test))」を使って一連の作業を自動化してみましょう。統合テストを使うと、アプリケーションの動作を端から端まで (end-to-end) シミュレートしてテストすることができます。まずは、site_layout
というテストのテンプレートを生成するところから始めてみます。
$ rails generate integration_test site_layout
invoke test_unit
create test/integration/site_layout_test.rb
このとき、Railsは与えられたファイル名の末尾に _test
という文字列を追加することに注目してください。
今回の目的は、アプリケーションのHTML構造を調べて、レイアウトの各リンクが正しく動くかどうかチェックすることです。つまり、
- ルートURL (Homeページ) にGETリクエストを送る
- 正しいページテンプレートが描画されているかどうか確かめる
- Home、Help、About、Contactの各ページへのリンクが正しく動くか確かめる
Railsの統合テストでは、上のステップをコードに落とし込んでいくことになります (リスト5.25)。具体的には、まずassert_template
メソッドを使って、Homeページが正しいビューを描画しているかどうか確かめます14。
require 'test_helper'
class SiteLayoutTest < ActionDispatch::IntegrationTest
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
リスト5.25では、assert_select
メソッドの高度なオプションを使っています (このメソッド自体はリスト3.22やリスト5.16でも登場しました)。 今回のケースでは、特定のリンクが存在するかどうかを、a
タグとhref
属性をオプションで指定して調べています。たとえば
assert_select "a[href=?]", about_path
上のコードでは、Railsは自動的にはてなマーク "?" をabout_path
に置換しています (このとき "about_path" 内に特殊記号があればエスケープ処理されます)。これにより、次のようなHTMLがあるかどうかをチェックすることができます。
<a href="/about">...</a>
一方で、ルートURLへのリンクは2つあることを思い出してください (1つはロゴに、もう1つはナビゲーションバーにあります)。このようなときは
assert_select "a[href=?]", root_path, count: 2
といった風に書くことで、リスト5.23で定義したHomeページのリンクの個数も調べることもできます
assert_select
には色々な指定の仕方があります。その代表例をいくつか表5.2で紹介します。assert_select
は柔軟でパワフルな機能ですが (ここでは紹介し切れないほど他にも多くのオプションがあります)、しかし経験的には、このメソッドで複雑なテストはしない方が賢明です。今回のようなレイアウト内で頻繁に変更されるHTML要素 (リンクなど) をテストするぐらいに抑えておくとよいです。
コード | マッチする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.25で追加した統合テストが通るかどうかは、次のようにRakeタスクを実行することで試すことができます。
$ bundle exec rake test:integration
統合テストが成功したら、今度はすべてのテストを流して成功するかどうか確かめてみてください。
$ bundle exec rake test
レイアウトのリンクをテストする統合テストが追加されたことで、リンクに間違った変更が加えられたらすぐに気付けるようになりました。
5.4 ユーザー登録: 最初のステップ
この節では、レイアウトとルーティングの取り組みにおける頂点として、ユーザー登録ページへのルーティングを作成します。そのために2番目のコントローラを作成することになります。これは、Webサイトでユーザー登録を行えるようにするための最初の重要な一歩となります。次の一歩であるユーザーのモデリングは第6章で行い、第7章でユーザー登録が完成します。
5.4.1 Usersコントローラ
3.2で、最初のコントローラであるStaticPagesコントローラを作成しました。今度は2番目のコントローラであるUsersコントローラを作成しましょう。1番目のときと同様、generate
を実行して、現時点での要求である新規ユーザー用のユーザー登録ページ (スタブ) を持つ、最も簡単なコントローラを作成します。Railsで好まれているRESTアーキテクチャの規約に従い、新規ユーザー用のアクションをnew
とします。したがって、generate controller
の引数にnew
を渡して、自動的にアクションを作成してみましょう。変更の結果をリスト5.28に示します。
new
アクションを追加)
$ rails generate 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
create test/helpers/users_helper_test.rb
invoke assets
invoke coffee
create app/assets/javascripts/users.js.coffee
invoke scss
create app/assets/stylesheets/users.css.scss
リスト5.28により、new
アクションを持つUsersコントローラ(リスト5.30)と、スタブのユーザービューを作成します(リスト5.31)。このとき、新しいUserページ用の小さなテスト (リスト5.32) も生成されていて、この時点ではパスするはずです。
$ bundle exec rake test
new
アクションを持つ最初のUsersコントローラ app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
end
end
new
アクション app/views/users/new.html.erb
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
test "should get new" do
get :new
assert_response :success
end
end
5.4.2 ユーザー登録用URL
5.4.1のコードにより、新規ユーザー用の動作するページが/users/new にできました。ここで表5.1を思い出していただきたいのですが、URLは/users/newではなく表のとおりに/signupにしたいと思います。リスト5.22の例に従い、ユーザー登録URL用にget ’/signup’
のルールを追加します (リスト5.33)。
Rails.application.routes.draw do
root 'static_pages#home'
get 'help' => 'static_pages#help'
get 'about' => 'static_pages#about'
get 'contact' => 'static_pages#contact'
get 'signup' => 'users#new'
end
次に、新しく定義された名前付きルートを使って、Homeページのボタンに適切なリンクを追加します。他のルートと同様、get ’/signup’
と記述したことでsignup_path
という名前付きルートができ、それをリスト5.34で使用します。signupページへのテストは演習に回すことにします (5.6)。
<div class="center jumbotron">
<h1>Welcome to the Sample App</h1>
<h2>
This is the home page for the
<a href="http://www.railstutorial.org/">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ページ用のカスタムスタブ (stub) のビューを追加します (5.35)。
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>This will be a signup page for new users.</p>
これで、少なくともサインインのルートを追加するまでの間、リンクと名前付きルートが完成しました(第8章)。結果を図5.9の新規ユーザーのページ (URI /signup) に示します。
5.5 最後に
この章では、アプリケーションのレイアウトを形にし、ルーティングを洗練させました。本書では、以後サンプルアプリケーションを肉付けすることに専念します。最初に、ユーザー登録、サインイン、サインアウトできるユーザーを追加します。次に、マイクロポストを追加します。最後に、他のユーザーをフォローできるようにします。
Gitを使っている方は、この時点でmasterブランチに変更をマージしてください。
$ bundle exec rake test
$ git add -A
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout
続いて、Bitbucketにプッシュします。
$ git push
最後に、Herokuへデプロイします。
$ git push heroku
デプロイが無事に終わると、本番環境でサンプルアプリケーションが動いているはずです (図5.10)。
5.5.1 本章のまとめ
- HTML5を使ってheaderやfooter、logoやbodyといったコンテンツのレイアウトを定義しました
- Railsのパーシャルは効率化のために使われ、別ファイルにマークアップを切り出すことができます
- CSSは、CSSクラスとidを使ってレイアウトやデザインを調整します
- Bootstrapフレームワークを使うと、いい感じのデザインを素早く実装できる
- SassとAsset Pipelineは、(開発効率のために切り分けられた) CSSの冗長な部分を圧縮し、本番環境に最適化した結果を出力する
- Railsのルーティングでは自由にルールを定義することができ、また、その際に名前付きルートも使えるようになる
- 統合テストは、ブラウザによるページ間の遷移を効率的にシミュレートする
5.6 演習
注: 『演習の解答マニュアル (英語)』にはRuby on Railsチュートリアルのすべての演習の解答が掲載されており、www.railstutorial.orgから購入して頂いた方は無料で手に入れることができます。
演習とチュートリアル本編の食い違いを避ける方法については、3.6のトピックブランチの演習に追加したメモをご覧ください。
- 5.2.2で触れたように、まずはリスト5.13のフッター用CSSをリスト5.15のSCSSに変更してみてください。
-
リスト5.25の統合テストに、
get
メソッドを使ってユーザー登録ページにアクセスし、ページタイトルが正しいかどうかチェックするテストコードを加えてください。 -
リスト5.36で示すように、Applicationヘルパーで使っている
full_title
ヘルパーを、test環境でも使えるようにすると便利です。こうしておくと、リスト5.37のようなコードを使って正しいタイトルをテストすることができます (ちなみにこれは前回の演習の応用でもあります)。ただし、これは完璧なテストではありません。たとえばベースタイトルに“Ruby on Rails Tutoial”といった誤字があったとしても、このテストでは発見することができないでしょう。この問題を解決するためには、full_title
ヘルパーに対するテストを書く必要があります。そのために、Applicationヘルパーをテストするファイルを作成し、リスト5.38のFILL_IN
の部分を適切なコードに置き換えてみてください。(ヒント: リスト5.38ではassert_equal <期待される値>, <実際の値>
といった形で使っていましたが、内部では==
演算子を使って、期待される値と実際の値を比較して正しいかどうかテストしています。)
ENV['RAILS_ENV'] ||= 'test'
.
.
.
class ActiveSupport::TestCase
fixtures :all
include ApplicationHelper
.
.
.
end
full_title
ヘルパーを使う GREEN 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'
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
get signup_path
assert_select "title", full_title("Sign up")
end
end
full_title
ヘルパーの単体テスト test/helpers/application_helper_test.rb
require 'test_helper'
class ApplicationHelperTest < ActionView::TestCase
test "full title helper" do
assert_equal full_title, FILL_IN
assert_equal full_title("Help"), FILL_IN
end
end
- Colm Tuiteの多大な貢献により、サンプルアプリケーションをBootstrap CSSのフレームワークに変換することができました。感謝します。↑
- Ruby on Railsチュートリアル のモックアップは、「Mockingbird」という素晴らしいモックアップ作成サービスで作られています。↑
- shimとshivという単語は、今回の用途ではどちらでも大丈夫です。shimを意味は「洗う機械、もしくは薄い物質を整理しフィットさせるためのモノ、あるいは服を削除すること」なので、意味合いとしては前者が正しいです。ちなみに後者は「ナイフ、もしくは武器として使う剃刀」という意味なので、おそらく原著者である Sjoerd Visscherのちょっとしたイタズラ心でしょう。↑
- CSSクラスは、Rubyのクラスとはまったく関係がありません。↑
- スペースを入れると見栄えが変わるかもしれませんが、3.4.1で触れたようにHTMLは重複する空白を無視するのでどちらでも大丈夫です。↑
- もしOS XのHomebrewが使えるようになっていれば、
brew install curl
というコマンドを打ってcurl
をインストールすることができます。 ↑ - 既にお気付きだと思いますが、
img
タグは<img>...</img>ではなく<img ... />と書きます。この書式に従うタグは閉じタグとして知られています。 ↑ - Asset PipelineではLessを使うこともできます。詳しくはless-rails-bootstrap gemを参照してください。↑
- もしこのステップが摩訶不思議に思えたら、次のように考えてみましょう。「私はただbootstrap-sassのREADMEファイルに従っているのだ」と。↑
- 多くのRails開発者は、異なるビューの間で共通に使用するパーシャルを保存するディレクトリとして、
shared
ディレクトリを使用します。著者は、複数のビューで共有するユーティリティパーシャルについてはshared
フォルダに保存し、文字どおり全ページ (サイトレイアウトの一部として) 共通のパーシャルについてはlayouts
ディレクトリへ保存することを好んでいます (shared
ディレクトリは第7章で作成します)。著者はこのように分割保存するのが論理的であると考えますが、shared
フォルダにすべて保存しても問題なく動作します。↑ -
footer
タグと.footer
クラスを両方使用していることについて疑問に思う方がいるかもしれません。その理由は、footerタグとする方が読み手にとって意味が明確であるのと、.footerクラスはBootstrapで使用するためです。footer
をdiv
に置き換えても動作は変わりません。↑ - このチュートリアル構成は、Michael Erasmusによる素晴らしいブログ記事「5分でわかるRails 3のAsset Pipeline (英語)」をもとにしています。詳細についてはRailsガイドの「アセットパイプライン」の項を参照してください。↑
- Sassでもサポートされている古い
.sass
というフォーマットでは、冗長性の少ない (括弧の少ない) 新しい言語を定義しますが、既存のプロジェクトには若干不便であり、既にCSSに慣れ親しんだ人にとっては学習が面倒でもあります。↑ - 何人かの開発者は「1つのテストに複数のアサーションを入れるべきではない」と強く主張するでしょう。 この演習は不必要に複雑で、もし各テストの直前に共通のセットアップ用タスクがあれば、たしかに不要な負荷がかかることでしょう。しかし、よく書かれたテストは一貫したストーリーのようになり、人間にとって理解しやすいです。ストーリーを独立した場面ごとに分割されてしまうと、物語調ではなくなってしまいます。このことから、複数のアサーションを1つのテストにまとめるようにして、(minitestを通して) Rubyにどのセリフで間違ったのかを話させるようにしています。↑
Railsチュートリアルは YassLab 社によって運営されています。
コンテンツを継続的に提供するため、書籍・動画・質問対応サービスなどもご検討していただけると嬉しいです。
研修支援や教材連携にも対応しています。note マガジンや YouTube チャンネルも始めたので、よければぜひ遊びに来てください!