Ruby on Rails チュートリアル

実例を使ってRailsを学ぼう

Michael Hartl (マイケル・ハートル)

第3版 目次

前書き

私が前にいた会社 (CD Baby) は、かなり早い段階でRuby on Railsに乗り換えたのですが、またPHPに戻ってしまいました (詳細は私の名前をGoogleで検索してみてください)。そんな私ですが、Michael Hartl 氏の本を強く勧められたので、その本を使ってもう一度試してみた結果、今度は無事に Rails に乗り換えることができました。それがこの Ruby on Rails チュートリアルという本です。

私は多くの Rails 関連の本を参考にしてきましたが、真の決定版と呼べるものは本書をおいて他にありません。本書では、あらゆる手順が Rails 流で行われています。最初のうちは慣れるまでに時間がかかりましたが、この本を終えた今、ついにこれこそが自然な方式だと感じられるまでになりました。また、本書は Rails 関連の本の中で唯一、多くのプロが推奨するテスト駆動開発 (TDD: Test Driven Development) を、全編を通して実践しています。実例を使ってここまで分かりやすく解説された本は、本書が初めてでしょう。極めつけは、Git や GitHub、Heroku の実例に含めている点です。このような、実際の開発現場で使わているツールもチュートリアルに含まれているため、読者は、まるで実際のプロジェクトの開発プロセスを体験しているかのような感覚が得られるはずです。それでいて、それぞれの実例が独立したセクションになっているのではなく、そのどれもがチュートリアルの内容と見事に一体化しています。

本書は、筋道だった一本道の物語のようになっています。私自身、章の終わりにある練習問題もやりながら、この Rails チュートリアルを3日間かけて一気に読破しました1。最初から最後まで、途中を飛ばさずにやるのが一番効果的で有益な読み方です。ぜひやってみてください。

それでは、楽しんでお読みください!

Derek Sivers (sivers.org) CD Baby 創業者

謝辞

Ruby on Rails チュートリアルは、私の以前の著書「RailsSpace」と、その時の共著者の Aurelius Prochazka から多くのことを参考にさせてもらっています。Aure には、RailsSpace での協力と本書への支援も含め、感謝したいと思います。また、RailsSpaceRails チュートリアルの両方の編集を担当して頂いた Debra Williams Cauley 氏にも謝意を表したく思います。彼女が野球の試合に連れて行ってくれる限り、私は本を書き続けるでしょう。

私にインスピレーションと知識を与えてくれた Rubyist の方々にも感謝したいと思います: David Heinemeier Hansson、Yehuda Katz、Carl Lerche、Jeremy Kemper、Xavier Noria、Ryan Bat、Geoffrey Grosenbach、Peter Cooper、Matt Aimonetti、Mark Bates、Gregg Pollack、Wayne E. Seguin、Amy Hoy, Dave Chelimsky、Pat Maddox、Tom Preston-Werner、Chris Wanstrath、Chad Fowler、Josh Susser、Obie Fernandez、Ian McFarland、Steven Bristol、Pratik Naik、Sarah Mei、Sarah Allen、Wolfram Arnold、Alex Chaffee、Giles Bowkett、Evan Dorn、Long Nguyen、James Lindenbaum、Adam Wiggins、Tikhon Bernstam、Ron Evans、Wyatt Greene、Miles Forrest、Pivotal Labs の方々、Heroku の方々、thoughtbot の方々、そして GitHub の方々、ありがとうございました。最後に、ここに書ききれないほど多くの読者からバグ報告や提案を頂きました。ご協力いただいた皆様のおかげで、本書の完成度をとことんまで高めることができました。

著者

マイケルハートル (Michael Hartl) は「Ruby on Rails チュートリアル」という Web 開発を始めるときに最もよく参考にされる本の著者です。また、Softcover という自費出版プラットフォームの共同創業者でもあります。以前は、(今ではすっかり古くなってしまいましたが)「RailsSpace」という本の執筆および開発に携わったり、また、 一時人気を博した Ruby on Rails ベースのソーシャルネットワーキングプラットフォーム「Insoshi」の開発にも携わっていました。なお、2011年には、Rails コミュニティへの高い貢献が認められて、Ruby Hero Award を受賞しました。ハーバード大学卒業後、カリフォルニア工科大学物理学博士号を取得し、起業プログラム Y Combinator の卒業生でもあります。

  1. 3日間で読破するのは異常です! 実際にはもっと時間をかけて読むのが一般的です。

第3章 ほぼ静的なページの作成

本章から、本格的なサンプルアプリケーションの開発を進めていきます。残りのチュートリアルでは、このアプリケーションを例題として扱って学習していくことになります。本書を通して開発するアプリケーションは、最終的にはユーザーやマイクロポスト、ログイン/ログアウトなどの認証機能を持ちますが、まずは簡単なトピックである「静的なページの作成」から始めます。非常に単純なページではありますが、静的なページを自分の手で作成することは良い経験になり、多くの示唆も得られます。私達がこれから開発するアプリケーションにとって最適なスタート地点といえるでしょう。

Rails はデータベースと連携して動的なWebサイトを開発するように設計されていますが、HTMLファイルだけで構成されている静的なページを作ることもできます。実際、Railsであえて静的なページを使用しておいて、後からほんの少し動的なコンテンツを追加することもできます。本章では、このような静的なページの作成について学んでいきます。本章ではそれと平行して、近年のプログラミングで不可欠となっている「自動化テスト」の雰囲気を掴んでいただきます。自動化テストを作成することで、コードが正しく動いていることが裏付けられます。さらに、良いテストを書くことで、自信をもってリファクタリングを行うことができます。たとえば、フォームの振る舞いを変更せずに、フォーム内で使われている関数を書き換えたいときに有用です。

3.1 セットアップ

2と同様に、新しいRailsプロジェクトを作成するところから始めます。今回はsample_appという名前にします (リスト3.1)1リスト3.1のコマンドを実行したときに「Could not find ’railties'」のようなエラーが発生した場合は、Railsのバージョンが正しくない可能性がありますので、リスト1.1のとおりに正しくコマンドを入力したかどうかを確認してください。

リスト3.1: サンプルアプリケーションを生成する
$ cd ~/workspace
$ rails _4.2.2_ new sample_app
$ cd sample_app/

(2.1でも説明したとおり、クラウドIDEをご利用の方は、このプロジェクトをこれまでの2つの章で作成したプロジェクトと同じワークスペースに置くことができます。このプロジェクトで特に新しいワークスペースを作成する必要はありません)。

次は、2.1と同じように、テキストエディタを使ってGemfileに必要なgemを書き足していきます。リスト3.2リスト1.5リスト2.1は基本的にまったく同じですが、testグループ内のgemだけが若干異なっています。ここではもう少し高度なテスト用オプションを設定しています (3.7) (: もしサンプルアプリケーションの開発で必要になるgemをすべて知りたい場合は、リスト11.67を参照してください。これが最終的なGemfileになります)。

リスト3.2: サンプルアプリケーション用のGemfile
source 'https://rubygems.org'

gem 'rails',        '4.2.2'
gem 'sass-rails',   '5.0.2'
gem 'uglifier',     '2.5.3'
gem 'coffee-rails', '4.1.0'
gem 'jquery-rails', '4.0.3'
gem 'turbolinks',   '2.3.0'
gem 'jbuilder',     '2.2.3'
gem 'sdoc',         '0.4.0', group: :doc

group :development, :test do
  gem 'sqlite3',     '1.3.9'
  gem 'byebug',      '3.4.0'
  gem 'web-console', '2.0.0.beta3'
  gem 'spring',      '1.1.3'
end

group :test do
  gem 'minitest-reporters', '1.0.5'
  gem 'mini_backtrace',     '0.1.3'
  gem 'guard-minitest',     '2.3.1'
end

group :production do
  gem 'pg',             '0.17.1'
  gem 'rails_12factor', '0.0.2'
end

前の2つの章と同様にbundle installを実行して、Gemfileで指定したgemをインストール、インクルードします。ただし、「--without production」オプション2を指定して、productionでしか使わないgemをインストールしないようにしておきます。

$ bundle install --without production

上のオプションを指定することで、PostgreSQL用のpg gemをdevelopment環境にインストールせず、代わりにSQLiteがdevelopment環境testing環境で使用されるようになります。Herokuでは、development環境とproduction環境とで異なるデータベースを使用することを非推奨としていますが、幸いにもこのサンプルアプリケーションでは両者の違いは生じません。また、SQLiteの方がPostgreSQLよりもローカルでのインストールや設定がずっと楽なので3、今回はことなるデータベースを使うことにします。ここで使用するGemfileで指定されているのと異なるバージョンのgem (Rails自身のgemを含む) をこれまでにインストールしていた場合は、以下のようにbundle updateを実行してgemを更新し、gemのバージョンを合わせておくとよいでしょう。

$ bundle update

ここまで進めたら、後はGitリポジトリを初期化するだけです。

$ git init
$ git add -A
$ git commit -m "Initialize repository"

最初のアプリケーションのときと同様に、まずはアプリケーションのルートディレクトリにあるREADMEファイルを更新して、具体的な作業内容をわかりやすく記入しておくことをおすすめします。最初にGitのコマンドでREADMEのファイル形式をRDocからMarkdownに変更します。

$ git mv README.rdoc README.md

続いてリスト3.3の内容をREADMEに記入します。

リスト3.3: サンプルアプリケーション向けに書き換えたREADME
# Ruby on Railsチュートリアル: サンプルアプリケーション

これは以下に基づいたサンプル・アプリケーションです
[*Ruby on Railsチュートリアル:
実例を使ってRailsを学ぼう*](http://railstutorial.jp/)
[Michael Hartl](http://www.michaelhartl.com/)著

最後に、変更をコミットします。

$ git commit -am "Improve the README"

1.4.4git commit -a -m "Message"というGitコマンドを実行したことを思い出してください。あのときは “すべてを変更” (-a) オプションとコミットメッセージを追加するオプション (-m) を使用しました。上で実行したコマンドで示したように、実はこれらの2つのオプションを1つにまとめてgit commit -am "Message"と実行することができます。

本書では今後もこのサンプルアプリケーションを使い続けるので、Bitbucket上にリポジトリを作成してプッシュしておくとよいでしょう。

$ git remote add origin git@bitbucket.org:<username>/sample_app.git
$ git push -u origin --all # リポジトリとブランチをすべてプッシュする

後で統合時に悩まずにすむよう、アプリをなるべく早い段階でHerokuにデプロイしておくとよいでしょう。12と同様に、リスト1.81.9の「Hello, world」の手順に従うことをお勧めします4。終わったら以下のように変更をコミットしてHerokuにプッシュします。

$ git commit -am "Add hello"
$ heroku create
$ git push heroku master

(1.5のときと同じように警告メッセージが表示されることがありますが、無視して構いません。この警告は7.5で解決する予定です)。これで、Herokuアプリのアドレス以外は1.18のとおりに表示されるはずです。

この後も、本チュートリアルを進めながらアプリケーションをこまめにプッシュ/デプロイすることをおすすめします。こうすることでリモートバックアップにもなり、production環境でのエラーを早めに確認することもできます (訳注: 最後にまとめてプッシュ/デプロイすると問題が同時多発して解決に手間取ることが考えられます)。なお、Herokuに展開するときにエラーが発生した場合は、以下のコマンドを実行して本番環境のログを取得してください。このログは、問題を特定するときに役立ちます。

$ heroku logs

: 今後Herokuで何らかの本番アプリケーションを運用する予定があるなら、7.5のproduction用Webサーバーの設定に必ず従ってください。

3.2 静的ページ

3.1の準備がすべて完了したら、いよいよサンプルアプリケーションの開発に取りかかりましょう。この節では、Railsのアクションビューを作成して、静的なHTMLのみのページを動的なページに作り変えるための最初の手順を進めます5。Railsのアクションはコントローラ (1.3.3で言うMVCの「C」) の中に置かれます。コントローラには、目的に沿って互いに関連したアクションが置かれます。コントローラについては2でも簡単に触れましたが、6で説明するREST アーキテクチャを読むと理解が深まります。一言で言うと、コントローラとは (基本的に動的な) Webページの集合を束ねるコンテナのことです。現在どのディレクトリで作業しているかがわからなくなった場合は、1.3 (図 1.4)を再度参照して、Rails のディレクトリ構造を確認してください。この節では、主にapp/controllersディレクトリやapp/viewsディレクトリ内で作業を進めます。

1.4.4で学んだことを思い出しましょう。Gitを使用する場合は、masterブランチでずっと作業するのではなく、その都度トピックブランチを作成して作業するのがよい習慣です。Gitでバージョン管理を行っているのであれば、以下のコマンドを実行して、静的なページ用のトピックブランチをチェックアウトしましょう。

$ git checkout master
$ git checkout -b static-pages

(1行目は、確実にmasterブランチに切り替えるために行っています。これにより、2行目のstatic-pagesトピックブランチがmasterから作成されるようになります。もしすでにmasterブランチにいる場合は、1行目のコマンドを実行する必要はありません)。

3.2.1 静的なページの生成

静的なページの作成は、2でscaffold生成に使用したgenerateスクリプトで、コントローラを生成することから始めます。このコントローラは静的なページを扱うためにしか使わないので、コントローラ名を「Static Pages」に決め、表記をキャメルケースStaticPagesにします。続いて、Homeページ、Helpページ、Aboutページに使用するアクションもそれぞれ作成することにし、アクション名はすべて小文字のhomehelpaboutにします。generateスクリプトではアクション名をまとめて指定することもできるので、コマンドラインでHomeページとHelpページ用のアクションもまとめて生成することにします。なお、Aboutページだけは学習のため、あえてコマンドラインでは作成せず、3.3で手動で追加することにします。これらの要素を盛り込んだStaticPagesコントローラ生成コマンドと実行結果をリスト3.4に示します。

リスト3.4: StaticPagesコントローラを生成する
$ rails generate controller StaticPages home help
      create  app/controllers/static_pages_controller.rb
       route  get 'static_pages/help'
       route  get 'static_pages/home'
      invoke  erb
      create    app/views/static_pages
      create    app/views/static_pages/home.html.erb
      create    app/views/static_pages/help.html.erb
      invoke  test_unit
      create    test/controllers/static_pages_controller_test.rb
      invoke  helper
      create    app/helpers/static_pages_helper.rb
      invoke    test_unit
      create      test/helpers/static_pages_helper_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/static_pages.js.coffee
      invoke    scss
      create      app/assets/stylesheets/static_pages.css.scss

追伸: rails grails generateコマンドの短縮形であり、Railsでサポートされている多数の短縮形のひとつです (3.1)。本チュートリアルではわかりやすさを重んじているため、こうしたコマンドは短縮せずに表記していますが、現実のRails開発者はほぼ間違いなく3.1の短縮形を常用しています。

完全なコマンド 短縮形
$ rails server $ rails s
$ rails console $ rails c
$ rails generate $ rails g
$ bundle install $ bundle
$ rake test $ rake
表3.1: Railsで使える短縮形の例

次に進む前に、StaticPagesコントローラファイルをGitリポジトリに追加しておきましょう。

$ git status
$ git add -A
$ git commit -m "Add a Static Pages controller"
$ git push -u origin static-pages

最後のコマンドでは、static-pagesトピックブランチをBitbucketにプッシュしています。以後は、単に以下を実行するだけで同じプッシュが行われるようになります。

$ git push

上のコミット〜プッシュの流れは、著者が実際の開発でよく使っていたパターンに基づいていますが、ここから先は途中でこのような指示をいちいち書くことはしませんので、各自こまめにプッシュするようにしてください。

リスト3.4では、コントローラ名をキャメルケース (訳注: 単語の頭文字を大文字にしてつなぎ合わせた名前) で渡していることに注目してください。こうすると、StaticPagesコントローラ名をスネークケース (訳注: 単語間にアンダースコアを加えて繋ぎ合わせた名前) にしたファイル static_pages_controller.rb を自動的に生成します。ただし、上のような命名は単なる慣習に過ぎません。実際、コマンドライン上で以下のようなスネークケースのコントローラ名を入力しても、

$ rails generate controller static_pages ...

先ほどと同様にstatic_pages_controller.rbというコントローラが生成されます。これは、Rubyがクラス名にキャメルケースを使う慣習があり (詳細は4.4で説明します)、また、キャメルケースの名前を使うことが好まれているためです。これらの慣習に必ず従わなければいけないということではありません。(同様にRubyでは、ファイル名をスネークケースで記述する慣習があります。このため Railsのgenerateスクリプトでは、 underscoreメソッドを使ってキャメルケースをスネークケースに変換しています。)

ところで、自動生成に失敗するようなことがあれば、元に戻す処理を学ぶ良い機会になります。以下のコラム3.1で元に戻す方法を紹介しています。

コラム3.1 元に戻す方法

どれほど十分に気を付けていたとしても、Railsアプリケーションの開発中に何か失敗してしまうことはありえます。ありがたいことに、Railsにはそのような失敗をカバーする機能がいくつもあります。

一般的なシナリオの1つは、生成したコードを元に戻したい場合です。たとえば、コントローラを生成した後で、もっといいコントローラ名を思い付き、生成したコードを削除したくなった場合などです。リスト3.4のように、Railsはコントローラ以外にも関連ファイルを大量に生成するので、生成されたコントローラファイルを削除するだけでは元に戻りません。自動生成されたコードを完全に元に戻すには、新規作成されたファイルを削除するほかに、既存のファイルに挿入されたコードも削除する必要があります (実際、2.22.3でも説明したように、rails generateを実行するとルーティングのroutes.rbファイルも自動的に変更されるので、これも元に戻さなくてはなりません)。このようなときは、「generate」という言葉に因んで、rails destroyというコマンドを実行することで元に戻すことができます。たとえば次の2つのコマンドは、自動生成と、それに対応する取り消し処理の例です。

  $ rails generate controller StaticPages home help
  $ rails destroy  controller StaticPages home help

なお第6章でも、以下のようにモデルを自動生成する方法を紹介します。

  $ rails generate model User name:string email:string

モデルの自動生成についても、同様の方法で元に戻すことができます。

  $ rails destroy model User

(上のコマンドからわかるように、モデル名以外の引数は不要です。その理由については第6章で説明します)。

また、第2章でも簡単に紹介しましたが、マイグレーションの変更を元に戻す方法も用意されています。詳細は第6章で説明します。簡単に言うと、まず以下のコマンドでデータベースのマイグレーションを変更できます。

  $ bundle exec rake db:migrate

以下のコマンドで1つ前の状態に戻すこともできます。

  $ bundle exec rake db:rollback

最初の状態に戻したい場合は、以下のコマンドを使います。

  $ bundle exec rake db:migrate VERSION=0

既にお気付きの方もいると思いますが、マイグレーションは逐次的に実行され、それぞれのマイグレーションに対してバージョン番号が付与されます。したがって、上記の0を別の数字に置き換えることによって、指定したバージョンの状態に戻すことができます。

開発中に袋小路に迷い込んでしまった場合でも、これらの機能を使えば元の状態を復元できます。

リスト3.4のようにStaticPagesコントローラを生成すると、(config/routes.rb)ファイルが自動的に更新されます (1.3.4のときと同様です)。このルーティングファイルはルーターの実装を受け持ち (2.11)、URLとWebページの対応関係を定義します。このルーティングファイルはRailsのconfigディレクトリの下に置かれます。このディレクトリには、Railsの設定ファイルがまとめて置かれます (3.1)。

images/figures/config_directory_3rd_edition
図3.1 サンプルアプリケーションのconfigディレクトリの内容

先ほどリスト3.4のようにhomeアクションとhelpアクションを生成したので、routesファイルにはそれぞれのアクションで使用されるルールが定義されています (リスト3.5)。

リスト3.5: StaticPagesコントローラ内のhomeアクションとhelpアクションで使用するルーティング config/routes.rb
Rails.application.routes.draw do
  get 'static_pages/home'
  get 'static_pages/help'
  .
  .
  .
end

ここで以下のルールに注目してみましょう。

get 'static_pages/home'

このルールは、/static_pages/homeというURLに対するリクエストを、StaticPagesコントローラのhomeアクションと結びつけています。具体的には、getと書くことで、GETリクエストに対して該当するアクションを結びつけています。なお、ここでいう GETリクエストとは、HTTP (HyperText Transfer Protocol) (コラム3.2) が対応しているメソッドの1つです。今回の場合は、StaticPagesコントローラ内にhomeアクションを追加したので、/static_pages/homeにアクセスすることでページを取得 (GET) できるようになりました。結果を確認するには、1.3.2に従って以下のようにRailsのdevelopmentサーバーを起動します。

$ rails server -b $IP -p $PORT    # ローカルサーバーの場合は`rails server`だけを実行する

/static_pages/homeにアクセスして結果を表示します (3.2)。

images/figures/raw_home_view_3rd_edition
図3.2 /static_pages/homeにアクセスした結果
コラム3.2 GETやその他のHTTPメソッドについて

HTTP (HyperText Transfer Protocol) には4つの基本的な操作があり、それぞれGETPOSTPATCHDELETEという4つの動詞に対応づけられています。クライアント (通常、FirefoxやSafariなどのWebブラウザ) とサーバー (ApacheやNginxなどのWebサーバー) は、上で述べた4つの基本操作を互いに認識できるようになっています(ローカル環境でRailsアプリケーションを開発しているときは、クライアントとサーバーが同じコンピュータ上で動いていますが、一般的には、それぞれ別のコンピュータで動作しているという点を理解しておいてください)。Railsを含む多くのWebフレームワークは、HTTPの各操作を発展させたREST アーキテクチャの影響を受けています。第2章でも簡単に触れましたが、第7章では、より深い内容について学びます。

GET は、最も頻繁に使用されるHTTP操作で、主にWeb上のデータを読み取る際に使われます。「ページを取得する」という意味のとおり、ブラウザはgoogle.comwikipedia.orgなどのWebサイトを開くたびにGETリクエストをサイトに送信します。Railsアプリケーションでは、POSTリクエストは何かを作成するときによく使われます (なお本来のHTTPでは、POSTを更新に使ってもよいとしています)。たとえば、ユーザー登録フォームで新しいユーザーを作成するときは、POSTリクエストを送信します。他にも、PATCHDELETEという2つの操作があり、それぞれサーバー上の何かを更新したり削除したりするときに使われます。これら2つの操作は、GETPOSTほどは使用されていません。これは、ブラウザがPATCHとDELETEをネイティブでは送信しないからです。しかし、Ruby on Railsなどの多くのWebフレームワークは、ブラウザがこれらの操作のリクエストを送信しているかのように見せかける技術 (偽装) を駆使して、PATCHとDELETEという操作を実現しています。結果として、Railsはこの4つのHTTPリクエスト (GETPOSTPATCHDELETE) を全てサポートできるようになりました。

このページがどのようにして表示されるのかを理解するために、まずはテキストエディタでStaticPagesコントローラを開いてみましょう。リスト3.6のような内容になっているはずです。ここで、第2章のUsersコントローラやMicropostsコントローラとは異なり、StaticPagesコントローラは一般的なRESTアクションに対応していないことに注意してください。これは、静的なページの集合に対しては、適切なアクションと言えます。言い換えると、RESTアーキテクチャは、あらゆる問題に対して最適な解決方法であるとは限らないということです。

リスト3.6: リスト3.4で生成されるStaticPagesコントローラ app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end
end

リスト 3.6classというキーワードから、static_pages_controller.rbStaticPagesControllerというクラスを定義していることがわかります。クラスは、関数 (メソッドとも呼ばれます) をまとめるときに便利な手法です。今回の例では、defというキーワードを使って、homeアクションやhelpアクションを定義しています。2.3.4で説明したように、山括弧<は、StaticPagesControllerApplicationControllerというRailsのクラスを継承していることを示しています。この後も説明しますが、今回作成したページには、Rails特有の機能が多数使用されています (具体的なクラスや継承については、4.4で詳しく説明します)。

今回のStaticPagesコントローラにあるメソッドは、以下のようにどちらも最初は空になっています。

def home
end

def help
end

純粋なRuby言語であれば、これらのメソッドは何も実行しません。しかし、Railsでは動作が異なります。StaticPagesControllerはRuby のクラスですが、ApplicationControllerクラスを継承しているため、StaticPagesControllerのメソッドは (たとえ何も書かれていなくても) Rails特有の振る舞いをします。具体的には、/static_pages/homeというURLにアクセスすると、RailsはStaticPagesコントローラを参照し、homeアクションに記述されているコードを実行します。その後、そのアクションに対応するビュー (1.3.3で説明したMVCのVに相当) を出力します。今回の場合、homeアクションが空になっているので、/static_pages/homeにアクセスしても、単に対応するビューが出力されるだけです。では、ビューはどのように出力されるのでしょうか。また、どのビューが表示されるのでしょうか。

リスト3.4をもう一度注意深く読んでみると、アクションとビューの関係性について理解できるでしょう。homeアクションは、home.html.erbというビューに対応しています。.erbの詳細については3.4で説明しますが、ファイル名に.htmlが含まれていることからわかるように、基本的にはHTMLと同じような構造になっています (リスト3.7)。

リスト3.7: Homeページ用に生成されたビュー app/views/static_pages/home.html.erb
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>

helpアクションに対応するビューも、上のコードと似ています (リスト3.8)。

リスト3.8: Helpページ用に生成されたビュー app/views/static_pages/help.html.erb
<h1>StaticPages#help</h1>
<p>Find me in app/views/static_pages/help.html.erb</p>

どちらのビューも単なるプレースホルダになっています。トップレベルの見出しがh1タグの中にあり、関連するファイルへの絶対パスがpタグの中に書かれています。

3.2.2 静的なページの調整

3.4からは (ほんの少しだけ) 動的なコンテンツを追加しますが、リスト3.7リスト3.8で見たように、重要なのは「Railsのビューの中には静的なHTMLがある」という点です。これは、Railsの知識が無くてもHomeページやHelpページを修正できることを意味しています。以下のリスト3.9リスト3.10がその一例です。

リスト3.9: HomeページのHTMLを修正する app/views/static_pages/home.html.erb
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>
リスト3.10: HelpページのHTMLを修正する app/views/static_pages/help.html.erb
<h1>Help</h1>
<p>
  Get help on the Ruby on Rails Tutorial at the
  <a href="http://railstutorial.jp/help">Rails Tutorial help section</a>.
  To get help on this sample app, see the
  <a href="http://railstutorial.jp"><em>Ruby on Rails Tutorial</em>
  book</a>.
</p>

リスト3.9リスト3.10の結果をそれぞれ3.33.4に示します。

images/figures/custom_home_page
図3.3 修正されたHomeページ
images/figures/custom_help_page_3rd_edition
図3.4 修正されたHelpページ

3.3 テストから始める

3.2.2でサンプルアプリのHomeページとHelpページを作成して中身も書き加えたので、今度はAboutページを同様に追加します。何らかの変更を行う際には、常に「自動化テスト」を作成して、機能が正しく実装されたことを確認する習慣をぜひ身に付けましょう。アプリケーションを開発しながらテストスイートをみっちり作成しておけば、いざというときのセーフティネットにもなり、それ自体がアプリケーションのソースコードの「実行可能なドキュメント」にもなります。テストを作成するということは、その分コードを余分に書くことになりますが、正しく行えば、むしろテストがないときよりも確実に開発速度がアップします。テストが揃っていれば、バグを追うために余分な時間を使わずに済むためです。そんなふうにうまくいくとは信じられない人もいるかもしれませんが、一度でもテスト作成が上達すれば間違いなくこのとおりになります。だからこそ、テスト作成の習慣をできるだけ早いうちに身につけることが重要なのです。

テストが重要であるという点ではRails開発者の意見はほぼ一致していますが、細かい点では異論が生じているのも確かです。特に、テスト駆動開発 (TDD)6 (テストの手法のひとつ: 最初に「正しいコードがないと失敗するテスト」を書き、次に本編のコードを書いてそのテストがパスするようにする) の是非については、当分議論が終わりそうにありません。筆者も悩んだ末、Ruby on Railsチュートリアルではこの点について「とにかく〜すべし」的な原理主義を避けることにしました。テストに関しては、原則として手軽かつ直感的なアプローチを採用し、必要に応じてTDDに切り替えるようにしています (コラム3.3)。

コラム 3.3 結局テストはいつ行えばよいのか

それではいつ、どんなふうにテストを行えばよいのでしょうか。この点を理解するために、テストを行う目的をもう一度確認してみましょう。著者は、テストには以下の3つのメリットがあると考えます。

  1. テストが揃っていれば、機能停止に陥るような回帰バグ (regression: 以前のバグが再発したり機能追加/変更の副作用が生じたりすること、先祖返りとも言う) を防止できる。
  2. テストが揃っていれば、コードを安全にリファクタリング (機能を変更せずにコードを改善すること) できる。
  3. テストコードは、アプリケーションコードから見ればクライアントとして動作するので、アプリケーションの設計やシステムの他の部分とのインターフェイスを決めるときにも役に立つ。

上の3つのメリットは、テストを先に書かなくても得ることができますが、それでもテスト駆動開発 (TDD) という手法をいつでも使えるようにしておけば、間違いなく多くの場面で役に立ちます。テストの手法やタイミングは、ある意味テストをどのぐらいすらすら書けるかで決まると言ってよいでしょう。たいていの開発者は、テストを書くのに慣れてくるとテストを先に書くようになります。その他にも、アプリケーションのコードと比べてテストがどのぐらい書きにくいか、必要な機能をどのぐらい正確に把握しているか、その機能が将来廃止される可能性がどのぐらいあるかによっても異なってくるでしょう。

こういうときのために、「テスト駆動」にするか「一括テスト」にするかを決める目安となるガイドラインがあると便利です。著者の経験を元に、以下のようにまとめてみました。

  • アプリケーションのコードよりも明らかにテストコードの方が短くシンプルになる (=簡単に書ける) のであれば、テストを先に書けるようになることを目指す。
  • 期待している動作がまだ固まりきっていないのであれば、先にアプリケーションのコードを書き上げ、続いて期待する動作をテストコードで記述することを目指す。
  • セキュリティが最重要課題であれば、セキュリティモデルでエラーが発生した場合のテストを最初に書くべき。
  • バグを見つけたら、そのバグを再現するテストを真っ先に書き、回帰バグを防ぐ体制を整えてからアプリケーションのコードの修正に取りかかる。
  • 将来変更の可能性が少しでもあるコード (HTML構造の細部など) があれば必ずテストを書く。
  • リファクタリングの前には必ずテストを書き、エラーを起こしそうなコードや、特に止まってしまいそうなコードを集中的にテストする。

上のガイドラインに従う場合、現実には最初にコントローラやモデルのテストを書き、続いて統合テスト (モデル/ビュー/コントローラにまたがる機能テスト) を書く、ということになります。また、不安定な要素が特に見当たらないアプリケーションや、(主にビューが) 頻繁に改定される可能性の高いアプリケーションのコードを書くときには、思い切ってテストを省略してしまうこともないわけではありません。

本書における主要なテストは、コントローラテスト (この節より)、モデルテスト (6より)、統合テスト (7より) の3つです。統合テストでは、ユーザーがWebブラウザでアプリケーションとやりとりする操作をシミュレートできるので特に強力です。統合テストは最終的にテスティングにおける最も主要な武器となりますが、まずは取っ付きやすいコントローラテストから始めることにしましょう。

3.3.1 最初のテスト

それではサンプルアプリケーションのAboutページの作成に取りかかります。やってみるとわかりますが、このページでは大したことは行わないので、このテストは驚くほど短く単純です。早速コラム3.3のガイドラインに沿って、テストを先に書くことにしましょう。続いてそのテストを実行して「失敗」することを確認し、実際のアプリケーションコードを書きます。

初めて書くテストがいきなり「テスト先行」というのは、Ruby on Railsの知識がある程度以上必要なため、少々ハードルが高い面もあります。今の段階でテストを書かせようとすると、尻込みしてしまう人もいるかもしれません。しかしご心配なく。面倒な部分は既にRailsが全部面倒を見てくれています。rails generate controller (リスト3.4) を実行した時点でテストファイルがちゃんと作成されているので、それを利用しましょう。

$ ls test/controllers/
static_pages_controller_test.rb

生成されたテストを見てみましょう (リスト3.11)。

リスト3.11: StaticPagesコントローラのデフォルトのテスト GREEN test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
  end

  test "should get help" do
    get :help
    assert_response :success
  end
end

現時点では、上のリスト3.11の文法をいきなり理解する必要はありません。今は「このファイルにはテストが2つ書かれている」ことを認識していただければ十分です。その2つのテストは、リスト3.4で生成したコントローラの2つのアクションであるHomeとHelpに対応して生成されたものです。それぞれのテストでは、アクションをgetして正常に動作することを確認します。この確認は「アサーション」(assertion: 主張、断言) と呼ばれる手法で行います。getは、HomeページやHelpページがいわゆる「GETリクエストを受け付ける」普通のWebページであるということを示します (コラム3.2)。その次の「response:success」は、実際にはHTTP のステータスコード (ここでは200 OK) を表します。つまり、以下のようなテストは

test "should get home" do
  get :home
  assert_response :success
end

言葉で表すと「Homeページのテスト。GETリクエストをhomeアクションに対して発行 (=送信) せよ。そうすれば、リクエストに対するレスポンスは[成功]になるはず。」となります。

テスティングサイクルの最初の一回しに取りかかる前に、まずは現在のテストスイートをそのまま実行して、問題なくパスすることを確認しておきます。テストの実行には、以下のようにrakeユーティリティを使用します (コラム2.1)7

リスト 3.12: GREEN
$ bundle exec rake test
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips

テストスイートは期待どおりパス GREEN します (パスしたときにも色を表示できるようにするには、3.7.1のminitestレポーターをオプションで追加する必要があります)。ところで、テストの実行にはある程度時間がかかります。これには2つの要因が絡んでいます: (1) Spring serverを起動してRails環境を事前読み込みするのに時間がかかる。ただしこれは最初の1回だけです。(2) Rubyそのものの起動に時間がかかる (2番目の要因については、3.7.3で紹介するGuardを導入することで改善できます)。

3.3.2 Red

コラム3.3で解説したように、テスト駆動開発のサイクルは「失敗するテストを最初に書く」「次にアプリケーションのコードを書いてパスさせる」「必要ならリファクタリングする」のように進みます。多くのテストツールでは、テストの失敗を「レッド」、成功したときを「グリーン」で表します。ここから、このサイクルを「レッド・グリーン・リファクタリング」と呼ぶこともあります。これに従って最初のサイクルを完了させましょう。まず失敗するテストを書いてREDになるようにします。テストをGREENにするのは3.3.3、リファクタリングは3.4.3で行います8

サイクルの記念すべき第一歩はAboutページ用の失敗するテストを書くことです。リスト3.11を参考にすれば、正しいテストコードを何となく想像できると思います。正しいテストコードをリスト3.13に示します。

リスト3.13: Aboutページのテスト RED test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
  end

  test "should get help" do
    get :help
    assert_response :success
  end

  test "should get about" do
    get :about
    assert_response :success
  end
end

リスト3.13のハイライト行を見ると、他のHomeページ用テストやHelpページ用テストとほとんど同じであることがわかります。違いは「home」や「help」の部分が「about」に変わっている点だけです。

テストを実行すると、期待どおり失敗します。

リスト3.14: RED
$ bundle exec rake test
3 tests, 2 assertions, 0 failures, 1 errors, 0 skips

3.3.3 Green

テストがめでたく失敗した (RED) ので、今度はこのテストのエラーメッセージを頼りにテストがパスする (GREEN) ようにコードを書くことで、Aboutページを実装します。

失敗したテストのエラーメッセージをもっと詳しく見ていきましょう9

リスト3.15: RED
$ bundle exec rake test
ActionController::UrlGenerationError:
No route matches {:action=>"about", :controller=>"static_pages"}

このエラーメッセージによれば、「指定されたアクション/コントローラの組み合わせに一致するルーティングが見当たらない」とあります。つまりルーティングファイルを修正する必要があるということです。リスト3.5のときと同じ要領で変更を行った結果をリスト3.16に示します。

リスト3.16: about用のルートを追加する RED config/routes.rb
Rails.application.routes.draw do
  get 'static_pages/home'
  get 'static_pages/help'
  get 'static_pages/about'
  .
  .
  .
end

リスト3.16のハイライト行では、/static_pages/aboutというURLへのGETリクエストが来たら、StaticPagesコントローラのaboutアクションに渡すようRailsに指示しています。

修正が終わったらテストスイートを再度実行します。まだREDのままです。しかし今度はメッセージが少し変わりました。

リスト3.17: RED
$ bundle exec rake test
AbstractController::ActionNotFound:
The action 'about' could not be found for StaticPagesController

このエラーメッセージから、「StaticPagesコントローラにaboutアクションがない」ということがわかります。リスト3.6homehelpと同じようにaboutアクションを追加します (リスト3.18)。

リスト3.18: aboutアクションが追加されたStaticPagesコントローラ RED app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController

  def home
  end

  def help
  end

  def about
  end
end

今度はどうでしょう。まだREDですが、エラーメッセージがまた少し変わりました。

$ bundle exec rake test
ActionView::MissingTemplate: Missing template static_pages/about

今度はテンプレートがないようです。Railsではテンプレートといえばすなわち「ビュー」のことです。3.2.1で説明したように、homeというアクションはhome.html.erbというビューに関連付けられます。このビューはapp/views/static_pagesにあるので、ここにabout.html.erbというファイルを作ればよさそうです。

ファイルの作成方法はシステムの設定によってさまざまですが、たいていのテキストエディタでは、ディレクトリをCtrl+クリックすればコンテキストメニューに「New File」のようなメニューが表示されます。あるいはエディタの[File]メニューでファイルを作成して、このディレクトリに保存しても構いません。個人的にはUnixのtouchコマンドでファイルを作成するのがかっこいいと思います。

$ touch app/views/static_pages/about.html.erb

touchコマンドは本来ファイルやディレクトリのタイムスタンプだけを更新するためのコマンドなのですが、ファイルが存在しない場合には空ファイルを作成するという一種の副作用があります (クラウドIDEをご利用の場合は、touchでファイル作成後に1.3.1のようにファイルツリーの更新が必要な場合があります)。

とにかくabout.html.erbを正しいディレクトリに作成できたので、リスト3.19のとおりにコードを入力します。

リスト3.19: Aboutページのコード GREEN app/views/static_pages/about.html.erb
<h1>About</h1>
<p>
  The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
  Tutorial</em></a> is a
  <a href="http://railstutorial.jp">book</a> and
  <a href="http://screencasts.railstutorial.org/">screencast series</a>
  to teach web development with
  <a href="http://rubyonrails.org/">Ruby on Rails</a>.
  This is the sample application for the tutorial.
</p>

今度はrake testの結果はGREENになるはずです。

リスト3.20: GREEN
$ bundle exec rake test
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips

もちろん、実際にブラウザを起動して、テストが正しく動いているかどうかを確かめることもできます (図3.5)。

images/figures/about_us_3rd_edition
図3.5 作成したAboutページ (/static_pages/about)

3.3.4 リファクタリング

テストがGREENになったので、安心してコードをリファクタリングできるようになりました。アプリケーションの開発が進むと、コードのどこからともなく「腐敗臭」が漂い始めます。コードや記法の統一が崩れて読みづらくなる、クラスやメソッドが何百行にも膨れ上がって読む気を削がれる、なぜこのコードがここにあるのか最早誰もその理由を思い出せなくなる、同じコードがあちこちにコピペされて少しずつ書き換えられ手に負えなくなる、などです。コンピュータにしてみればどんなに汚らしいコードであろうと、そこにあるがままに実行するだけですが、人間はそういうわけにはいきません。こまめにリファクタリングを繰り返してコードを常にすみずみまで美しくコンパクトに保ち、他の開発者や未来の自分の開発意欲を阻喪することのないようにしなければなりません。このサンプルアプリは生まれたてなので、今のところリファクタリングの必要な箇所はほぼどこにも見当たりません。しかし「一匹いれば30匹いると思え」、コードの腐敗臭はどんな小さな隙間からも忍び寄ってきます。こまめなリファクタリングの習慣をできるだけ早いうちに身につけるためにも、少々無理やりに3.4.3から始めることにします。

3.4 少しだけ動的なページ

静的なページのアクションやビューをいくつか作成できたので、今度はそれをほんの少しだけ動的にしてみましょう。ページの内容に応じて、ページのタイトルを自ら書き換えて表示するようにします。タイトルを自動で変えるぐらいのことが真の動的コンテンツと呼べるかどうかは議論の余地があると思いますが、いずれにしろこのページは、第7章で紹介する本格的な動的コンテンツの基礎となります。

ここでの目標は、Homeページ、Helpページ、Aboutページをそれぞれ編集し、最終的にページごとに異なるタイトルを表示することです。ここではビューの<title>タグの内容を変更します。多くのブラウザでは、titleタグの内容をブラウザウィンドウの上部にウィンドウタイトルとして表示します。titleタグは、いわゆるSEO (search engine optimization: 検索エンジン最適化) においても重要な役割を果たします。今度は「レッド・グリーン・リファクタリング」のサイクルをすべて行うことにします。ページタイトルの簡単なテストを書き (RED)、3つのページにタイトルを追加し (GREEN)、レイアウトファイルを活用してコードの重複を解決します (リファクタリング)。本節の終わりまでに、3つの静的ページのタイトルを「<ページ名> | Ruby on Rails Tutorial Sample App」という形式に変更します。「<ページ名>」の部分がページに応じて変わります (3.2)。

前述のrails newコマンド (リスト3.1) を実行すると、レイアウトもデフォルトで作成されます。ここでは学習のため、一時的に以下のようにファイル名を変更します。

$ mv app/views/layouts/application.html.erb layout_file   # temporary change

普通は、実際のアプリケーション開発時に上のような操作を行うことはありません。ここでは、レイアウトファイルの役割をよりわかりやすく説明するために、最初にレイアウトファイルを無効にしています。

ページ URL 基本タイトル 追加タイトル
Home /static_pages/home "Ruby on Rails Tutorial Sample App" "Home"
Help /static_pages/help "Ruby on Rails Tutorial Sample App" "Help"
About /static_pages/about "Ruby on Rails Tutorial Sample App" "About"
表3.2 サンプルアプリケーションの (ほぼ) 静的なページ。

3.4.1 タイトルをテストする (Red)

ページタイトルを追加するために、典型的なWebページの構造を今一度おさらいしておきましょう (リスト3.21)。

リスト3.21: Webページの典型的なHTML構造
<!DOCTYPE html>
<html>
  <head>
    <title>Greeting</title>
  </head>
  <body>
    <p>Hello, world!</p>
  </body>
</html>

リスト3.21の構造には次のものが含まれています。1) document type (doctype) は使用するHTMLのバージョン (ここではHTML510) をブラウザに対して宣言します。2) headセクション。ここではtitleタグに囲まれた「Greeting」(=あいさつ) という文字があります。3) bodyセクション。ここには「Hello, world!」という文字列があります。「Hello, world!」はp (paragraph) タグの中にあります (HTMLではスペースやタブは無視されるので、インデントはあってもなくても大丈夫ですが、インデントがある方がHTMLのデータ構造を理解しやすくなります)。

3.2の各タイトルについて簡単なテストを書きます (リスト3.13)。このテストで使用しているassert_selectメソッドでは、特定のHTMLタグが存在するかどうかをテストします (この種のアサーションメソッドはその名から「セレクタ」と呼ばれることもあります)11

assert_select "title", "Home | Ruby on Rails Tutorial Sample App"

上のセレクタは、<title>タグ内に「Home | Ruby on Rails Tutorial Sample App」という文字列があるかどうかをチェックします。同じ要領で3つの静的ページを書き換えます (リスト3.22)。

リスト3.22: StaticPagesコントローラのタイトルをテストする RED test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  test "should get home" do
    get :home
    assert_response :success
    assert_select "title", "Home | 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
end

(上のテストコードで繰り返し使われている「Ruby on Rails Tutorial Sample App」という文字列を一刻も早くリファクタリングしたくてたまらない方には、3.6の演習をおすすめします。)

リスト3.22どおりにテストを作成すると、テストスイートはREDになります。

リスト3.23: RED
$ bundle exec rake test
3 tests, 6 assertions, 3 failures, 0 errors, 0 skips

3.4.2 タイトルを追加する (Green)

今度は各ページにタイトルを追加して、3.4.1のテストがパスするようにしましょう。リスト3.21の基本HTML構造をカスタムのHomeページ (リスト3.9) に追加すると、リスト3.24のようになります。

リスト3.24: 完全なHTML構造を備えたHomeページのビュー RED app/views/static_pages/home.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Home | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>
    <p>
      This is the home page for the
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
      sample application.
    </p>
  </body>
</html>

このページの表示を3.6に示します12

images/figures/home_view_full_html
図3.6 タイトルが付いたHomeページ

Helpページ (リスト3.10) やAboutページ (リスト3.19) についても、同じ要領でリスト3.25リスト3.26のようなコードに変更します。

リスト 3.25: 完全なHTML構造を備えたHelpページのビュー RED app/views/static_pages/help.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Help | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Help</h1>
    <p>
      Get help on the Ruby on Rails Tutorial at the
      <a href="http://railstutorial.jp/help">Rails Tutorial help
      section</a>.
      To get help on this sample app, see the
      <a href="http://railstutorial.jp"><em>Ruby on Rails
      Tutorial</em> book</a>.
    </p>
  </body>
</html>
リスト3.26: 完全なHTML構造を備えたAboutページのビュー GREEN app/views/static_pages/about.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>About | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>About</h1>
    <p>
      The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
      Tutorial</em></a> is a
      <a href="http://railstutorial.jp">book</a> and
      <a href="http://screencasts.railstutorial.org/">screencast series</a>
      to teach web development with
      <a href="http://rubyonrails.org/">Ruby on Rails</a>.
      This is the sample application for the tutorial.
    </p>
  </body>
</html>

これでテストスイートはGREENになるはずです。

リスト3.27: GREEN
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips

3.4.3 レイアウトと埋め込みRuby (Refactor)

この節では、Railsのコントローラとアクションを使って3つの有効なページを生成することでさまざまなことを達成しました。しかしそれらは単純な静的ページであり、またRailsの能力を十分に発揮できていません。しかも、コードが甚だしく重複しています。

  • ページのタイトルがどれもほぼ同じ (完全にではないが)。
  • 「Ruby on Rails Tutorial Sample App」という文字が3つのタイトルで繰り返し使われている。
  • HTMLの構造全体が各ページで重複している。

同じコードを繰り返すことはRubyの「DRY」(Don't Repeat Yourself: 繰り返すべからず) という原則に反します。この節では、繰り返しを追放してコードをDRY (=よく乾かす) にしましょう。最後に3.4.2のテストを実行して、タイトルを壊していないことを確認します。

上の話と一見矛盾するようですが、最初にコードを若干追加して、現在は「ほぼ」同じになっているページのタイトルを「完全に」同じにしておきます。この方が、コードの重複を一括で取り除けるからです。

重複を取り除くテクニックのひとつとして、ビューで「埋め込みRuby」(Embedded Ruby) を使用できます。Home、Help、Aboutページには可変要素があるので、Railsのprovide関数を使用してタイトルをページごとに変更します。それでは、home.html.erbビューのコードを、リスト3.28のように、タイトルに含まれる"Home"という文字を置き換え、動作を確認しましょう。

リスト3.28: タイトルにERBコードを使用したHomeページのビュー GREEN app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Sample App</h1>
    <p>
      This is the home page for the
      <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
      sample application.
    </p>
  </body>
</html>

リスト3.28は、ERBと呼ばれている、Rubyの埋め込みコードの最初の例です (これで、HTMLビューのファイルの拡張子が.html.erbとなっている理由をおわかりいただけたと思います)。ERBはWebページに動的な要素を加えるときに使うテンプレートシステムです13

<% provide(:title, "Home") %>

上のコードでは<% ... %>という記法が使用されており、その中からRailsのprovide関数を呼び出しています。関数の引数では、"Home"という文字列と:titleというラベルを関連付けています14。そしてタイトルの部分では、上の記法と連携する「<%= ... %>」というよく似た記法を使用し、その中でRubyのyield関数を呼び出しています15。この関数によって、テンプレートのその部分に実際のタイトルが挿入されます。

<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>

この2つのERBの違いは次のとおりです。<% ... %>と書くと、中に書かれたコードを単に実行するだけで何も出力しません。<%= ... %>のように等号を追加すると、中のコードの実行結果がテンプレートのその部分に挿入されます。ERBでビューをこのように書き換えても、ページの表示結果は以前とまったく同じです。タイトルの可変部分がERBによって動的に生成されている点だけが異なります。

3.4.2のテストを実行してこの改修を確認すれば、今度もGREENになるはずです。

リスト3.29: GREEN
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips

続いて、HelpページとAboutページも同様に変更します (リスト3.30リスト3.31)。

リスト3.30: タイトルにERBコードを使用したHelpページのビュー GREEN app/views/static_pages/help.html.erb
<% provide(:title, "Help") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>Help</h1>
    <p>
      Get help on the Ruby on Rails Tutorial at the
      <a href="http://railstutorial.jp/help">Rails Tutorial help
      section</a>.
      To get help on this sample app, see the
      <a href="http://railstutorial.jp"><em>Ruby on Rails
      Tutorial</em> book</a>.
    </p>
  </body>
</html>
リスト3.31: タイトルにERBコードを使用したAboutページのビュー GREEN app/views/static_pages/about.html.erb
<% provide(:title, "About") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    <h1>About</h1>
    <p>
      The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
      Tutorial</em></a> is a
      <a href="http://railstutorial.jp">book</a> and
      <a href="http://screencasts.railstutorial.org/">screencast series</a>
      to teach web development with
      <a href="http://rubyonrails.org/">Ruby on Rails</a>.
      This is the sample application for the tutorial.
    </p>
  </body>
</html>

タイトルの可変部分をERBを使って置き換えたので、現在それぞれのページはだいたい以下のような構造になっています。

<% provide(:title, "The Title") %>
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
  </head>
  <body>
    Contents
  </body>
</html>

こうして見ると、HTMLの構造はtitleタグの内容も含めてどのページも完全に同じです。異なる点があるとすれば、bodyタグの内側のコンテンツだけです。

これはもうリファクタリングしてHTMLの重複した構造をDRYにするしかないでしょう。ご想像のとおり、Railsにはそのためにapplication.html.erbという名前のレイアウトファイルがあります。最初3.4でこのレイアウトファイルの名前をわざわざ変えておきましたが、いよいよ以下のコマンドでファイル名を元に戻すことにしましょう。

$ mv layout_file app/views/layouts/application.html.erb

このレイアウトファイルを有効にするには、前述のデフォルトのタイトル部分を以下のERBコードに差し替えます。

<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>

変更の結果、レイアウトファイルはリスト3.32のようになります。

リスト3.32: サンプルアプリケーションのレイアウト GREEN app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
    <%= stylesheet_link_tag    'application', media: 'all',
                                              'data-turbolinks-track' => true %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
    <%= csrf_meta_tags %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>

上のコードにある、以下の特殊なコードにご注目ください。

<%= yield %>

このコードは、各ページの内容をレイアウトに挿入するためのものです。ここでは、このコードの詳細な動作を正確に理解することは重要ではありません。レイアウトを使用するうえでは、/static_pages/homeにアクセスすると、home.html.erbの内容がHTMLに変換され、<%= yield %>の位置に挿入されるということだけ理解しておけば問題ありません。

Railsのデフォルトのレイアウトには、以下の行が追加されていることにもご注目ください。

<%= stylesheet_link_tag ... %>
<%= javascript_include_tag "application", ... %>
<%= csrf_meta_tags %>

上の3つのERBは、それぞれスタイルシート、JavaScript、csrf_meta_tagsメソッドをページ内で展開するためのものです。スタイルシートとJavaScriptは、Asset Pipeline (5.2.1) の一部です。csrf_meta_tagsは、Web攻撃手法のひとつであるクロスサイトリクエストフォージェリー (cross-site request forgery: CSRF)を防ぐために使われるRailsのメソッドです。

もちろん、リスト3.28リスト3.30リスト3.31のビューには、レイアウトと重複するHTMLがまだ残っているので、それらを削除して、内部のコンテンツだけ残します。この改修が終わると、 リスト3.33リスト3.34リスト3.35のように実に簡潔で美しいコードになります。

リスト3.33: HTML構造を削除したHomeページ GREEN app/views/static_pages/home.html.erb
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
  This is the home page for the
  <a href="http://www.railstutorial.org/">Ruby on Rails Tutorial</a>
  sample application.
</p>
リスト3.34: HTML構造を削除したHelpページ GREEN app/views/static_pages/help.html.erb
<% provide(:title, "Help") %>
<h1>Help</h1>
<p>
  Get help on the Ruby on Rails Tutorial at the
  <a href="http://railstutorial.jp/help">Rails Tutorial help section</a>.
  To get help on this sample app, see the
  <a href="http://railstutorial.jp"><em>Ruby on Rails Tutorial</em>
  book</a>.
</p>
リスト3.35: HTML構造を削除したAboutページ GREEN app/views/static_pages/about.html.erb
<% provide(:title, "About") %>
<h1>About</h1>
<p>
  The <a href="http://www.railstutorial.org/"><em>Ruby on Rails
  Tutorial</em></a> is a
  <a href="http://railstutorial.jp">book</a> and
  <a href="http://screencasts.railstutorial.org/">screencast series</a>
  to teach web development with
  <a href="http://rubyonrails.org/">Ruby on Rails</a>.
  This is the sample application for the tutorial.
</p>

上のように定義されたビューは、Home、Help、Aboutページの表示は以前と変わりませんが、コードの重複が大きく削減されました。

この節で行ったようなちっぽけなリファクタリングですら、実際にやってみると大小さまざまなエラーが発生します。ベテラン開発者ほどこのことを骨の髄まで理解しており、どんな小さなリファクタリングでもあなどったりしません。テストスイートをきちんと整備しておくことがいかに重要であるか、皆さんにもご理解いただけると思います。開発のごく初期の段階なら全ページを目視でひとつひとつ確認して回ることもできるかもしれませんが、そんな方法ではじきに手に負えなくなります。このアプリでは必要なテストスイートが整備されているので、今度もGREENになることを確認するだけでOKです。

リスト3.36: GREEN
$ bundle exec rake test
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips

もちろん厳密に言えば、テストがパスしたというだけではそのコードが本当に正しいのかどうかの証明にはなりません。しかし正しいコードに確実に近づくことができ、正しい可能性も上がります。何よりも、テストがあれば今後発生するバグを防ぐためのセーフティネットになります。

3.4.4 ルーティングの設定

サイトのページのカスタマイズが終わって、テストスイートも軌道に乗ってきたので、今のうちにアプリケーションルートのルーティングを設定しておきましょう。1.3.42.2.2でやったように、ルーティングを設定するにはroutes.rbファイルを編集して、ルート「/」とWebページを結び付けます。結び付ける相手はHomeページです (3.1でApplicationコントローラにhelloアクションを追加した場合は、今のうちにアクションを削除しておくことをおすすめします)。変更結果をリスト3.37に示します。ここでは、リスト3.5getルールを以下のコードに置き換えています。

root 'static_pages#home'

上のルールに置き換えると、static_pages/homeというURLからstatic_pages#homeというコントローラ/アクションへの対応付けが変わり、ルート「/」へのGETリクエストがStaticPagesコントローラのhomeアクションにルーティングされます。変更後のルーティングファイルを3.7に示します。リスト3.37のコードにすると、static_pages/homeにアクセスしても動作しなくなります。

リスト3.37: HomeページをルートURLに設定する config/routes.rb
Rails.application.routes.draw do
  root 'static_pages#home'
  get  'static_pages/help'
  get  'static_pages/about'
end
images/figures/home_root_route
図3.7 ルートURLにアクセスするとHomeページが表示される

3.5 最後に

はたから見れば、皆さんがこの章で結局どんなことを達成できたのかさっぱりわからないかもしれません。静的なページをあれこれ作り替えて、ほぼ静的なページにしただけなのでしょうか。もちろんそんなことはありません。皆さんはこの章でRailsのコントローラ、アクション、ビューの開発をひととおり行ったことで、これから動的なコンテンツをどしどしサイトに追加するための準備がすっかり整ったのです。残る課題は、皆さんがこのチュートリアルをいかに最後までやりぬくか、それだけであると言ってよいでしょう。

次の章に進む前に、差分をコミットしてmasterブランチにマージしておきましょう。3.1では、静的ページの開発のためのGitブランチを用意しました。ここまでの作業内容をコミットしていない場合、作業の区切りをつけるためにもコミットしましょう。

$ git add -A
$ git commit -m "Finish static pages"

次にmasterブランチに移動し、1.4.416と同じ要領で差分をマージします。

$ git checkout master
$ git merge static-pages

このように中継点まで達したら、コードをリモートリポジトリにアップロードしておくとよいでしょう (1.4.3の手順に従っていれば、リモートリポジトリはBitBucketを使用することになるでしょう)。

$ git push

また、この時点でHerokuにデプロイしてみてもよいでしょう。

$ bundle exec rake test
$ git push heroku

デプロイする前にテストを走らせていますが、こういった習慣を身につけておくと開発に役立ちます。

3.5.1 本章のまとめ

  • 新しいRailsアプリケーションをゼロから作成したのはこれで3度目。今回も必要なgemのインストール、リモートリポジトリへのプッシュ、production環境まで行った。
  • コントローラを新規作成するためのrailsのスクリプトはrails generate controller ControllerName <action name (省略可)>。訳注: コントローラ名はキャメルケース、アクション名はスネークケースにする。
  • 新しいルーティングはconfig/routes.rbファイルで定義する。
  • Railsのビューでは、静的HTMLの他にERB (埋め込みRuby: Embedded RuBy) も使用できる。
  • 常に自動化テストを使用して新機能開発を進めることで、自信を持ってリファクタリングできるようになり、回帰バグもいちはやくキャッチできるようになる。
  • テスト駆動開発では「レッド・グリーン・リファクタリング」サイクルを繰り返す。
  • Railsのレイアウトでは、アプリケーションのページの共通部分をテンプレートに置くことでコードの重複を解決することができる。

3.6 演習

: 『演習の解答マニュアル (英語)』にはRuby on Railsチュートリアルのすべての演習の解答が掲載されており、www.railstutorial.orgで原著を購入いただいた方には無料で配布しています (訳注: 解答は英語です)。

以後本チュートリアルの演習を解く際には、以下のように演習用トピックブランチを別途作成してそこで行うことをおすすめします。

$ git checkout static-pages
$ git checkout -b static-pages-exercises

トピックブランチを分けておくことで、チュートリアル本編との食い違いを避けることができます。

満足のゆく解ができたら、リモートリポジトリにプッシュしてもよいでしょう (リモートリポジトリがある場合)。

<solve first exercise>
$ git commit -am "Eliminate repetition (solves exercise 3.1)"
<solve second exercise>
$ git add -A
$ git commit -m "Add a Contact page (solves exercise 3.2)"
$ git push -u origin static-pages-exercises
$ git checkout master

(最後の行では、この後の開発準備のためにmasterブランチをチェックアウトしていますが、チュートリアル本編への影響を避けるため、演習で行った変更はmasterにマージしていません)。今後の章では、ブランチやコミットメッセージはもちろん異なりますが、基本的なアイディアは同じです。

  1. StaticPagesコントローラのテスト (リスト3.22) にも重複があることにお気付きでしょうか。特に「Ruby on Rails Tutorial Sample App」を全てのタイトルテストでそのまま使っています。専用のsetup関数 (テストの設定用関数、個別のテストの前に必ず毎回実行される) を使用してこの重複を解消し、テスト修正後もリスト3.38のテストがGREENになることを確認します (なお、リスト3.38ではインスタンス変数 (2.2.24.4.5) と文字列の式展開 (4.2.2) を使用しています)。
  2. サンプルアプリケーションにContact (問い合わせ先) ページを作成してください17リスト3.13を参考にして、/static_pages/contactというURLのページに「Contact | Ruby on Rails Tutorial Sample App」というタイトルが存在するかどうかを確認するテストを最初に作成しましょう。3.3.3でAboutページにやったのと同じように、Contactページにもリスト3.39のコンテンツを表示しましょう (リスト3.39にはリスト3.38のような修正は行われていないので、そのままコピペしても動きません)。
リスト3.38: 基本タイトルを含めたStaticPagesコントローラのテスト GREEN test/controllers/static_pages_controller_test.rb
require 'test_helper'

class StaticPagesControllerTest < ActionController::TestCase

  def setup
    @base_title = "Ruby on Rails Tutorial Sample App"
  end

  test "should get home" do
    get :home
    assert_response :success
    assert_select "title", "Home | #{@base_title}"
  end

  test "should get help" do
    get :help
    assert_response :success
    assert_select "title", "Help | #{@base_title}"
  end

  test "should get about" do
    get :about
    assert_response :success
    assert_select "title", "About | #{@base_title}"
  end
end
リスト3.39: 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="http://www.railstutorial.org/#contact">contact page</a>.
</p>

3.7 高度なセットアップ

この追加の節は、Ruby on Railsチュートリアルスクリーンキャストシリーズ (原著者の主催する有料スクリーンキャスト: 英語のみ) で使用するテスト用設定について解説します。大きく3つに分かれます: 高度なパス/失敗表示 (3.7.1)、テスト失敗時の大量のバックトレースメッセージをフィルタするユーティリティ (3.7.2)、ファイルの変更を検出して、必要なテストだけを自動実行してくれる「自動テスト実行ユーティリティ」(3.7.3)。この節で参考までに示したコードはそれなりに高度なので、今すぐ理解できるようになる必要はありません。

この節の変更はmasterブランチで行う必要があります。

$ git checkout master

3.7.1 minitestレポーター

Railsのデフォルトのテストで、必要に応じてREDGREENを表示するためには、リスト3.40のコードをテスト用ヘルパーファイルに追加するだけです18。このコードでは、リスト3.2で追加したminitest-reporters gemを利用しています。

リスト3.40: REDGREENを表示できるようにする test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!

class ActiveSupport::TestCase
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical
  # order.
  fixtures :all

  # Add more helper methods to be used by all tests here...
end

この変更により、Cloud IDE上の表示がREDからGREENに変わります (3.8)。

images/figures/red_to_green
図3.8: Cloud IDE上で表示をREDからGREENに変える

3.7.2 Backtrace silencer

テストが失敗した時に、テスト失敗の道筋をアプリケーション全体にわたってたどるスタックトレース (バックトレース) が表示されます。バックトレースは問題を追跡するうえでは非常に便利なのですが、クラウドIDEなど一部のシステムでは、このトレースがgemの依存関係やRails自身にまで及ぶことがあります。そうなると大量のスタックトレースが出力されて非常に不便です。gemの依存関係を調べているのでもなければ、開発しているアプリケーションで問題の原因を追跡中に大量のメッセージが出力されても、邪魔なだけです。

こうした不要な出力行を除去するために、バックトレースをフィルタします。これを行うにはmini_backtrace gem (リスト3.2) とbacktrace silencerを組み合わせます。クラウドIDEの場合、そうした不要な行ではほとんどの場合rvm (=Ruby Version Manager) という文字がパスに含まれているので、これを利用してフィルタします (リスト3.41)。

リスト3.41: RVMをフィルタするbacktrace silencerを追加する config/initializers/backtrace_silencers.rb
# Be sure to restart your server when you modify this file.

# You can add backtrace silencers for libraries that you're using but don't
# wish to see in your backtraces.
Rails.backtrace_cleaner.add_silencer { |line| line =~ /rvm/ }

# You can also remove all the silencers if you're trying to debug a problem
# that might stem from framework code.
# Rails.backtrace_cleaner.remove_silencers!

リスト3.41のコメント冒頭にあるように、backtrace silencerを追加した後は必ずRails webサーバーを再起動してください。

3.7.3 Guardによるテストの自動化

rake testコマンドは、テストをする度にコマンドラインに移動して手動でコマンドを実行しなければならない点が面倒です。この不便さを取り除くために、Guardを使ってテストを自動的に実行させるようにしてみましょう。Guardは、ファイルシステムの変更を監視し、たとえばstatic_pages_test.rbファイルなどを変更すると自動的にテストを実行してくれるツールです。また、テストファイルだけでなく、home.html.erbファイルが変更されるとstatic_pages_test.rbが自動的に実行されるようにGuardを設定することもできます。

実はすでに、リスト3.2Gemfileguard gemをアプリケーション内に取り込んでいます。したがって、あとは初期化するだけで動かすことができます。

$ bundle exec guard init
Writing new Guardfile to /home/ubuntu/workspace/sample_app/Guardfile
00:51:32 - INFO - minitest guard added to Guardfile, feel free to edit it

統合テストとビューが更新されたら自動的に適切なテストが実行されるように、生成されたGuardfileを編集します (リスト3.42)。(やや長くて応用的な設定なので、リスト3.42をコピペしてしまった方がよいでしょう)

リスト3.42: カスタマイズしたGuardfile.
# Defines the matching rules for Guard.
guard :minitest, spring: true, all_on_start: false do
  watch(%r{^test/(.*)/?(.*)_test\.rb$})
  watch('test/test_helper.rb') { 'test' }
  watch('config/routes.rb')    { integration_tests }
  watch(%r{^app/models/(.*?)\.rb$}) do |matches|
    "test/models/#{matches[1]}_test.rb"
  end
  watch(%r{^app/controllers/(.*?)_controller\.rb$}) do |matches|
    resource_tests(matches[1])
  end
  watch(%r{^app/views/([^/]*?)/.*\.html\.erb$}) do |matches|
    ["test/controllers/#{matches[1]}_controller_test.rb"] +
    integration_tests(matches[1])
  end
  watch(%r{^app/helpers/(.*?)_helper\.rb$}) do |matches|
    integration_tests(matches[1])
  end
  watch('app/views/layouts/application.html.erb') do
    'test/integration/site_layout_test.rb'
  end
  watch('app/helpers/sessions_helper.rb') do
    integration_tests << 'test/helpers/sessions_helper_test.rb'
  end
  watch('app/controllers/sessions_controller.rb') do
    ['test/controllers/sessions_controller_test.rb',
     'test/integration/users_login_test.rb']
  end
  watch('app/controllers/account_activations_controller.rb') do
    'test/integration/users_signup_test.rb'
  end
  watch(%r{app/views/users/*}) do
    resource_tests('users') +
    ['test/integration/microposts_interface_test.rb']
  end
end

# Returns the integration tests corresponding to the given resource.
def integration_tests(resource = :all)
  if resource == :all
    Dir["test/integration/*"]
  else
    Dir["test/integration/#{resource}_*.rb"]
  end
end

# Returns the controller tests corresponding to the given resource.
def controller_test(resource)
  "test/controllers/#{resource}_controller_test.rb"
end

# Returns all tests for the given resource.
def resource_tests(resource)
  integration_tests(resource) << controller_test(resource)
end

上のコードにある以下の行にご注目ください。

guard :minitest, spring: true, all_on_start: false do

この行ではGuardからSpringサーバーを使用して読み込み時間を短縮しています (SpringはRailsの機能のひとつです)。また、開始時にテストスイートをフルで実行しないようGuardに指示しています。

Guard使用時のSpringとGitの競合を防ぐには、.gitignoreファイルにspring/ディレクトリを追加します。.gitignoreはGitの設定ファイルのひとつで、ここで指定されたファイルはGitレポジトリに追加されなくなります。クラウドIDEでは以下の操作を行います。

  1. ナビゲーションパネルの右上のにある歯車アイコンをクリックします (3.9)。
  2. [Show hidden files] を選択して、アプリケーションのルートディレクトリにある.gitignoreファイルを表示します (3.10).
  3. .gitignoreファイル (3.11) をダブルクリックして開き、リスト3.43のように更新します。
images/figures/file_navigator_gear_icon
図3.9 ファイルナビゲーターにある (あまり目立たない) ギアのアイコン
images/figures/show_hidden_files
図3.10 ファイルナビゲーター内の隠しファイルを表示する
images/figures/gitignore
図3.11 隠れている.gitignoreファイルを表示する
リスト3.43: .gitignoreにSpringを追加する
# See https://help.github.com/articles/ignoring-files for more about ignoring
# files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
#   git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config.
/.bundle

# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal

# Ignore all logfiles and tempfiles.
/log/*.log
/tmp

# Ignore Spring files.
/spring/*.pid

Springサーバーは本節の執筆時点では若干不安定な点が残っていて、Springのプロセスが起動したまま多数残留すると、テストのパフォーマンスが低下してしまうことがあります。テストの実行が異常に遅くなってきたと感じたら、システムプロセスをチェックしてSpringを必要に応じてkillするとよいでしょう (コラム3.4)。

コラム3.4 Unixのプロセス

LinuxやOS XなどのUnix系システムは、ユーザータスクやシステムタスクはプロセス (process) と呼ばれる一種のコンテナの内部で実行されます。システム上で動いているすべてのプロセスは、psコマンドにauxオプションを付けて実行することで確認できます。

  $ ps aux

プロセスの種類を指定してフィルタするには、psの結果をUnixの「パイプ」|でつないで、パターンマッチャーであるgrepに渡します。

  $ ps aux | grep spring
  ubuntu 12241 0.3 0.5 589960 178416 ? Ssl Sep20 1:46
  spring app | sample_app | started 7 hours ago

表示結果の中で重要なのは最初の列の数値です。これはプロセスid、略してpidと呼ばれるものです。不要なプロセスを排除するには、killコマンドでpidを指定し、Unixのkillコード (ここでは15ですがシステムによって異なります) を発行します。

  $ kill -15 12241

行儀の悪いRailsサーバーなどのプロセスをkillする際には、上のようにひとつずつkillすることをおすすめします。Railsサーバーのpidを知るには、ps aux | grep server)などと実行します。しかし時には特定の名前を持つプロセスをまとめてkillしたいこともあります。しつこいspringプロセスたちをひとつずつkillするのは大変面倒です。一括killを行うには、最初にspringコマンドそのものでプロセスを停止しておく必要があります。

  $ spring stop

このコマンドが効かないことも多いので、そのときはいよいよpkillコマンドでspringの名前を指定してkillします。

  $ pkill -15 -f spring

開発中に動作がおかしくなったりプロセスがフリーズしていると思えたら、すぐにps auxで状態を確認し、kill -15 <pid>pkill -15 -f <プロセス名>でクリーンアップしましょう。

Guardの設定が完了したら、新しいターミナルを開き (1.3.2でやったようにRailsサーバーのターミナルと別にするのがポイントです)、以下をコマンドラインで実行します

$ bundle exec guard

リスト3.42のルールは本チュートリアルに最適化したものなので、たとえばコントローラのファイルを変更すると、Guardは即座にそれを検出して、そのコントローラの統合テストを自動実行します。テストを変更ファイルだけではなく、フルで実行したい場合は、guard>プロンプトでReturnキーを押します (このとき、Springサーバーに接続できないなどのエラーが表示されることがあります。問題を修正するには、もう一度Returnキーを押します)。

Guardを終了するにはCtrl-Dキーを押します。Guardに他のマッチャーを追加する方法については、リスト3.42の例、Guard READMEGuard wikiを参照してください。

  1. クラウドIDEをお使いの場合は「Goto Anything」コマンド (ファイル名の一部を入力するだけでその場所にジャンプする) が重宝します。「hello」アプリ「toy」アプリ「sample」アプリには同じファイル名が多数あるため、これらのアプリを同じプロジェクトに置くとファイルを見つけにくくなることがあります。たとえば「Gemfile」というファイル名を検索すると、GemfileGemfile.lockを含め、候補が6つも表示されてしまいます。そこで、この先に進む前に先の2つのアプリを思い切って削除しておくとよいでしょう。アプリを削除するには、workspaceディレクトリに移動してrm -rf hello_app/ toy_app/コマンドを実行します(1.1)。これらのアプリを既にBitbucketのリポジトリにプッシュしてあるなら、それを利用していつでもアプリを復元できます (その必要があればですが)。
  2. この--without productionオプションを一度実行すると「記憶される」ことにご注意ください。つまり、次回以降bundle installを実行すると、このオプションが暗黙で自動適用されます。
  3. 最終的には皆さんがPostgreSQLをdevelopment環境にインストールして設定できるようになるのが理想ですが、今は時期尚早であると考えます。実際に必要が生じたときは「install configure postgresql <自分のシステム>」や「rails postgresql setup」でググって各自挑戦してみてください (クラウドIDEの場合は<自分のシステム>にUbuntuと指定します)。
  4. 2でも指摘したとおり、主な理由は、デフォルトのRailsページはHerokuで破損してしまうことが多く、そのままだとデプロイが成功したのか失敗したのかがわかりにくいためです。
  5. ここで静的なページを作るために採用した方法は、おそらく最もシンプルな方法です。ただし他にも方法はあります。最適な方法は状況によって異なり、たとえば極めて多数の静的なページを1つのStaticPagesコントローラだけまかなおうとすると重荷になる可能性があります。今回はいくつかの静的なページを作るだけなので、重荷にはなりません。もし多数の静的なページが必要になる場合は、high_voltage gem を調べてみてください。なお、この問題には (やや古いですが) 有益な議論があります。 詳しくは hasmanythroughに投稿された記事「simple pages」 (英語) を読んでみてください。
  6. Rails生みの親であるDavid Heinemeier Hansson (通称DHH) の有名な記事『TDDは死んだ。テスティングに栄光あれ』(英語) を参照。
  7. 2.2でも説明したように、システム環境によってはbundle execが追加不要なこともあります。クラウドIDE (1.2.1) も追加不要なシステムのひとつです。しかしここでは省略せずにコマンドを記述しています。著者の場合、原則としてbundle execは追加せずに実行し、うまくいかないときだけbundle execを追加して様子を見る、ということをよく行っています。
  8. rake testはデフォルトで、テストの失敗を赤色で表示しますが、テストがパスしても緑色で表示しません。色もちゃんと表示したい場合は3.7.1をご覧ください。
  9. システムによっては、ソースコードのエラーパスを追跡する「スタックトレース」または「バックトレース」と呼ばれるメッセージが大量に表示されることがあります。この場合、かなり上にスクロールする必要があるかもしれません。バックトレース出力を絞り込んで不要な行が表示されないようにしたい場合は、3.7.2をご覧ください。
  10. HTMLの仕様は時とともに変わる可能性があると思っておく方がよいでしょう。今後もブラウザでなるべく正しくページを表示できるように、doctypeを明示的に宣言しています。追加属性がまったくないシンプルな「<!DOCTYPE html>」は、最新標準であるHTML5の特徴です。
  11. minitestで利用できるアサーションのリストについては、Railsガイドの「Rails テスティングガイド」をご覧ください。
  12. 本書のスクリーンショットでは原則としてGoogle Chromeを使用していますが、Chromeのタブはタイトルを表示しきれないので、3.6では代わりにSafariを使用しています。
  13. 2番目に人気のテンプレートとしてHamlがあり (注意: "HAML"ではありません) 、筆者は個人的にHamlの方が気に入っています。残念ながら十分に普及していないため、初級者向けチュートリアルの採用は見送りました。
  14. Railsでの開発経験者であれば、この時点でcontent_forの使用を検討すると思いますが、残念ながらAsset Pipelineと併用すると正常に動作しないことがあります。provide関数はcontent_forの代替です。
  15. Rubyを勉強したことのある方であれば、Railsはブロックの内容をyieldしていると推測することでしょう。そして、その推測はおそらく正しいでしょう。しかし、Rails開発のためにこれらの詳細を知る必要はありません。
  16. コミット時に「マージするとSpringのプロセスID (pid) ファイルが上書きされる可能性があります」のようなエラーメッセージが表示される場合は、コマンドラインでrm -f *.pidを実行してpidファイルを削除してください。
  17. この演習は5.3.1の節に解答があります。
  18. リスト3.40のコードには、シングルクオーテーション (') とダブルクオーテーション (") の両方が含まれています。これは、rails newで生成されたコードはシングルクオーテーションを使っていますが、minitestレポーターのドキュメントではダブルクオーテーションを使っていることが原因です。Rubyでは、この2つのクオーテーションを併用することが一般的です。詳しくは4.2.2で解説します。 
Railsチュートリアルは,Ruby/Rails のアジャイル開発を得意とする YassLab によって運営・保守されております.
継続的に良いコンテンツを提供する為に,電子書籍スクリーンキャストのご購入を検討して頂けると幸いです m(_ _)m
スポンサーシップや商用利用などに関するご相談がありましたら,お問い合わせページよりお気軽にご連絡ください :)