第3章 ほぼ静的なページの作成
Cloud9のコンソールubuntu:~/environment $ の後に下記コマンドでアプリ作成
$ rails _6.0.3_ new sample_app
作成したsample appディレクトリへ下記コマンドで移動
$ cd sample_app
サンプルアプリケーション用のGemfileを編集する
Sample_appディレクトリ内にあるGemfileを開いて下記のように編集する
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem 'rails', '6.0.3'
gem 'puma', '4.3.6'
gem 'sass-rails', '5.1.0'
gem 'webpacker', '4.0.7'
gem 'turbolinks', '5.2.0'
gem 'jbuilder', '2.9.1'
gem 'bootsnap', '1.4.5', require: false
group :development, :test do
gem 'sqlite3', '1.4.1'
gem 'byebug', '11.0.1', platforms: [:mri, :mingw, :x64_mingw]
end
group :development do
gem 'web-console', '4.0.1'
gem 'listen', '3.1.5'
gem 'spring', '2.1.0'
gem 'spring-watcher-listen', '2.0.1'
end
group :test do
gem 'capybara', '3.28.0'
gem 'selenium-webdriver', '3.142.4'
gem 'webdrivers', '4.1.2'
gem 'rails-controller-testing', '1.0.4'
gem 'minitest', '5.11.3'
gem 'minitest-reporters', '1.3.8'
gem 'guard', '2.16.2'
gem 'guard-minitest', '2.4.6'
end
group :production do
gem 'pg', '1.1.4'
end
Windows ではタイムゾーン情報用の tzinfo-data gem を含める必要があります
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
Gemfileで指定したgemのインストールをする、ただし、--without productionオプションを使い、production環境でしか使わないgemはインストールしないようにする。
$ bundle install --without production
上記コマンド入力後bundle updateを実行する
ここまで出来たらGitリポジトリを初期化する
$ git init
初期化
$ git add -A
追加
$ git commit -m "Initialize repository"
コメント
サンプルアプリケーション向けにREADME.mdファイルを下記の通り書き換える
Ruby on Rails チュートリアルのサンプルアプリケーション
これは、次の教材で作られたサンプルアプリケーションです。
Ruby on Rails チュートリアル
(第6版)
Michael Hartl 著
ライセンス
Ruby on Rails チュートリアル内にある
ソースコードはMITライセンスとBeerwareライセンスのもとで公開されています。
詳細は LICENSE.md をご覧ください。
使い方
このアプリケーションを動かす場合は、まずはリポジトリを手元にクローンしてください。
その後、次のコマンドで必要になる RubyGems をインストールします。
$ bundle install --without production
その後、データベースへのマイグレーションを実行します。
$ rails db:migrate
最後に、テストを実行してうまく動いているかどうか確認してください。
$ rails test
テストが無事に通ったら、Railsサーバーを立ち上げる準備が整っているはずです。
$ rails server
詳しくは、Ruby on Rails チュートリアル
を参考にしてください。
書き終えたら変更をコミットする
$ git commit -am "Improve the README
ここまでをGitHub上にリポジトリを作成し、リモートにもpushする。
$ git remote add origin https://github.com/<あなたのGitHubアカウント名>/sample_app.git
$ git push -u origin master
Username for 'https://github.com/mizumanjyu/sample_app.git':
と表示されるので文字通りgithubのUsernameを入力しエンター、次に
Password for 'https://mizumanjyu@github.com/mizumanjyu/sample_app.git':
と表示されるので、githubのパスワードを入力、今現在パスワードではなく、トークンを作成し入力する、この時入力しても何も表示されないが確かに入力されているのでエンターを押すとpushされる。
Cloud9への接続を許可するためにconfig/environments/development.rbの内容を編集する。
後でProduction環境にプッシュしたときに悩まないよう、作成したアプリを早い段階で本番環境であるHerokuへデプロイしておくと良い、しかしデプロイしても現段階のデータ内容では確認しにくいのでhelloアクションを作成しApplicationコントローラに追加してみる。
app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
def hello
render html: "hello, world!"
end
end
ルートルーティングを設定
config/routes.rb
Rails.application.routes.draw do
root 'application#hello'
end
ここまでの変更をコミットしてGitHubとHerokuへプッシュする
$ git commit -am "Add hello"
$ git push
$ heroku create
$ git push heroku master
$ heroku logs # 直近のイベントを表示する
$ heroku logs --tail # イベント発生のたびに自動表示する(Ctrl-Cで終了)
演習
1.Markdown記法のREADME(リスト 3.3)がHTMLとして正しくGitHub上で描画されているか、確認してみてください。
pushしてあるGitHubのリポジトリにある当該アプリを開くと編集されたREADME.mdファイルが確認できる。
2.本番環境(Heroku)のルートURLにアクセスして、デプロイが成功したかどうか確かめてみてください。
HerokuのアプリからOpenAppを開くとデプロイしてるかどうか下記の通り確認できる。はず。
Gitを使う場合、masterブランチで作業するのではなく、その都度トピックブランチを作成して作業するのが良い習慣らしい。なので静的なページ用のトピックブランチをチェックアウトする。
$ git checkout -b static-pages
静的なページの生成
コントローラ名は「Static Pages」に決め、表記をキャメルケースのStaticPagesにし、Homeページ、Helpページ、Aboutページ、に使うアクションもそれぞれ作成することにして、アクション名はすべて小文字のhome、help、aboutにする。generateスクリプトではアクション名をまとめて指定することもできるので、HomeページとHelpページ用のアクションでは作成せず、この先の学習のため、あえてコマンドラインでは作成しない。
$ rails generate controller StaticPages home help
この時点で上記コマンドを入力したら下記の様なエラーが発生
ubuntu:~/environment/sample_app (static-pages) $ rails generate controller StaticPages home help
warning Integrity check: System parameters don't match
error Integrity check failed
error Found 1 errors.
========================================
Your Yarn packages are out of date!
Please run yarn install --check-files
to update.
To disable this check, please change check_yarn_integrity
to false
in your webpacker config file (config/webpacker.yml).
yarn check v1.22.5
info Visit https://yarnpkg.com/en/docs/cli/check for documentation about this command.
なので、上記にあるように下記コマンドを実行
yarn install --check-files
改めて下記コマンドを入力するとコントローラが作成完了する。
$ rails generate controller StaticPages home help
次に進む前にGitリポジトリに追加しておく
$ git add -A
$ git commit -m "Add a Static Pages controller"
$ git push -u origin static-pages
もとに戻す方法
例:コントローラ自動作成と取り消し処理のコマンド
$ rails generate controller StaticPages home help
$ rails destroy controller StaticPages home help
例:マイグレーションの変更を元に戻す方法
$ rails db:migrate
元に戻したいときは db:rollbackで一つ前に戻す。
$ rails db:rollback
最初の状態に戻したいときは、 VERSION=0オプションを使う。
$ rails db:migrate VERSION=0
StaticPagesコントローラを生成すると、(config/routes.rb)ファイルが自動的に更新される。
今回はStaticPagesコントローラ内にhomeアクションを追加したので/static_pages/homeにアクセスするとページを取得(GET)できるようになっているので、rails serverを起動するとプレビューで確認できる。
$ rails server
演習
1.Fooというコントローラを作成し、その中にbarとbazアクションを追加してみてください。
$ rails generate controller Foo bar baz
で作成される
2.コラム3.1で紹介したテクニックを駆使して、Fooコントローラとそれに関連するアクションを削除してください。
ターミナルは一度実行したコマンドを上下カーソルで呼び出せので、先ほど作成時に実行したコマンドのgenerateをdestroyに変更して実行すれば削除される。
rails destroy controller Foo bar baz
静的なページの調整
HomeページのHTMLを修正する
app/views/static_pages/home.html.erb
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
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="https://railstutorial.jp/help">Rails Tutorial help page</a>.
To get help on this sample app, see the
<a href="https://railstutorial.jp/#ebook"><em>Ruby on Rails Tutorial</em>
book</a>.
</p>
###テストから始める###
今度はあえてgenerateで作成しなかったAboutページを追加する。
何らかの変更を行う際には、常に「自動化テスト」を作成して昨日が正しく実装されたか確認する習慣を身に付けることが必須。アプリケーションを開発しながらテストスイート(Test Suite)をみっちり作成しておけば、いざというときのセーフティネットにもなる。それ自体が実行可能なドキュメントにもなる。
###最初のテスト###
$ ls test/controllers/
static_pages_controller_test.rb
StaticPagesコントローラのデフォルトのテスト GREEN
test/controllers/static_pages_controller_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
test "should get home" do
get static_pages_home_url
assert_response :success
end
test "should get help" do
get static_pages_help_url
assert_response :success
end
end
test "should get home" do
get static_pages_home_url
assert_response :success
end
上記を言葉で表すと「Homeページのテスト。GETリクエストをhomeアクションに対して発行(=送信)せよ。そうすれば、リクエストに対するレスポンスは[成功]になるはず」という意味。
テストを書くサイクルに入る前に、今現在あるテストスイートをそのまま実行してみる。問題なくパスすることを確認する。下記railsコマンド
$ rails db:migrate # システムによっては必要
$ rails test
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
###Red###
テスト駆動開発のサイクルは「失敗するテストを最初に書く」「次にアプリケーションのコードを書いて成功させる(パスさせる)」「必要ならリファクタリングする」のように進める。
最初のサイクルはAboutページ用の失敗するテストを書く。
AboutページのテストRED
test/controllers/static_pages_controller_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
test "should get home" do
get static_pages_home_url
assert_response :success
end
test "should get help" do
get static_pages_help_url
assert_response :success
end
test "should get about" do
get static_pages_about_url
assert_response :success
end
end
上記の通りaboutページのテストを先に作成しただけだとテストは予定通り1 errorsとなる。
RED
$ rails test
3 tests, 2 assertions, 0 failures, 1 errors, 0 skips
###about用のルートを追加するRED###
config/routes.rb
Rails.application.routes.draw do
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
root 'application#hello'
end
###aboutアクションが追加されたStaticPagesコントローラRED###
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
end
エラー内容
ActionController::MissingExactTemplate: ActionController::MissingExactTemplate: StaticPagesController#about is missing a template for request formats: text/html
今度のエラー内容はテンプレートが無い、Railsでは、テンプレートは「ビュー」を指す。app/views/static_pagesディレクトリに、about.html.erbを作る。
$ touch app/views/static_pages/about.html.erb
###AboutページのコードGREEN###
app/views/static_pages/about.html.erb
<h1>About</h1>
<p>
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
is a <a href="https://railstutorial.jp/#ebook">book</a> and
<a href="https://railstutorial.jp/screencast">screencast</a>
to teach web development with
<a href="https://rubyonrails.org/">Ruby on Rails</a>.
This is the sample application for the tutorial.
</p>
###少しだけ動的なページ###
ここの目標は Homeページ、Helpページ、Aboutページをそれぞれ編集して、最終的にページごとに異なるタイトルを表示する。ここでは
タグの内容を変更する。rails newコマンドを実行すると、レイアウトも自動的にデフォルトで作成されているので一時的にapplication.html.erbファイルの名前をlayout_fileに変更する
$ mv app/views/layouts/application.html.erb layout_file
###StaticPagesコントローラのタイトルをテストするRED###
test/controllers/static_pages_controller_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Home | Ruby on Rails Tutorial Sample App"
end
test "should get help" do
get static_pages_help_url
assert_response :success
assert_select "title", "Help | Ruby on Rails Tutorial Sample App"
end
test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title", "About | Ruby on Rails Tutorial Sample App"
end
end
この時点でテストを実行しても各ページの
タグ内に指定された文字列が入ってないのでREDになる予定。RED
$ ubuntu:~/environment/sample_app (static-pages) $ rails test
3 tests, 6 assertions, 3 failures, 0 errors, 0 skip
###タイトルを追加する(Green)###
###完全な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="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
</body>
</html>
###完全な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="https://railstutorial.jp/help">Rails Tutorial help
page</a>.
To get help on this sample app, see the
<a href="https://railstutorial.jp/#ebook">
<em>Ruby on Rails Tutorial</em> book</a>.
</p>
</body>
</html>
###完全なHTML構造を備えたAboutページのビューRED###
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>
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
is a <a href="https://railstutorial.jp/#ebook">book</a> and
<a href="https://railstutorial.jp/screencast">screencast</a>
to teach web development with
<a href="https://rubyonrails.org/">Ruby on Rails</a>.
This is the sample application for the tutorial.
</p>
</body>
</html>
以上、テストで指定した3つのページの
タグ内に文字列を追加したのでテストではGREENになるはず。Finished in 0.05352s
3 tests, 6 assertions, 0 failures, 0 errors, 0 skip
なった。
###演習###
1.StatcPagesコントローラのテストには繰り返しがあった。特に「Ruby on Rails Tutorial Sample App」と言う基本タイトルは各テストで毎回同じ内容を書いてしまってる。そこでsetupと言う特別なメソッド(各テストが実行される直前で実行されるメソッド)を使って、この問題を解決。
###基本タイトルを使ったStaticPagesコントローラのテストGREEN###
test/controllers/static_pages_controller_test.rb
require 'test_helper'
class StaticPagesControllerTest < ActionDispatch::IntegrationTest
def setup
@base_title = "Ruby on Rails Tutorial Sample App"
end
test "should get home" do
get static_pages_home_url
assert_response :success
assert_select "title", "Home | #{@base_title}"
end
test "should get help" do
get static_pages_help_url
assert_response :success
assert_select "title", "Help | #{@base_title}"
end
test "should get about" do
get static_pages_about_url
assert_response :success
assert_select "title", "About | #{@base_title}"
end
end
上記、コピペせずにaboutページのコードのところ、#{base_title}として@忘れでエラーでた。すぐ解決したけど、ほんの些細な事でもエラーが出るのは良い。
###レイアウトと埋め込みRuby(Refactor)###
この節では、Railsコントローラとアクションを使って3つの有効なページを生成することで様々なことを達成した、しかし単純な静的ページである。またRailsの能力を十分に発揮できてないし、コードが甚だ重複している。
-ページのタイトルがどれもほとんど同じ
-「Ruby on Rails Tutorial Sample App」という文字が3つのタイトルで繰り返し使われてる。
-HTMLの構造全体が各ページで重複している
なので最初に若干のコードを追加して各ページのタイトルを完全に一致させる。
重複を取り除く1つとして、ビューで「埋め込みRuby」(Embedde Ruby)がつかえる。Home、Help、Aboutページには可変要素があるので、RubyのProvideメソッドを使ってタイトルをページごとに変更する。
###タイトルにERBを使ったHomeページのビューGREEN###
<% 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="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
</body>
</html>
<% provide(:title, "Home") %>
上コードでは「<% ... %>」という記法が使われている。その中からRailsのProvideメソッドを呼び出している。メソッドの引数では、"Home"という文字列と:titleというラベルを関連付けている。そしてタイトルの部分では、上の記法と連携する「<%= ...%>」という似た記法を使い、その中でRubyのyieldメソッドを呼び出している。このメソッドで、テンプレートのその部分に実際のタイトルが挿入されます。
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
$rails test
こうしてみると、HTMLの構造はtitleタグの内容も含めてどのページも完全に同じ。異なる点はBodyタグの内側のコンテンツだけ。
続いて、HelpとAboutページも同様に変更する。
###タイトルにERBを使ったHelpページビューGREEN###
<% 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="https://railstutorial.jp/help">Rails Tutorial help
section</a>.
To get help on this sample app, see the
<a href="https://railstutorial.jp/#ebook">
<em>Ruby on Rails Tutorial</em> book</a>.
</p>
</body>
</html>
###タイトルにERBを使ったAboutページのビューGREEN###
<% provide(:title, "About") %>
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
</head>
<body>
<h1>About</h1>
<p>
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
is a <a href="https://railstutorial.jp/#ebook">book</a> and
<a href="https://railstutorial.jp/screencast">screencast</a>
to teach web development with
<a href="https://rubyonrails.org/">Ruby on Rails</a>.
This is the sample application for the tutorial.
</p>
</body>
</html>
ここまで済んだらリファクタリングしてHTMLの重複した構造をDRYにするしかない、そのためにRailsにはapplication.html.erbという名前のレイアウトファイルがある。以前ファイル名を変えたものをもとに戻す。
$ mv layout_file app/views/layouts/application.html.erb
元に戻したファイル内の
タグの中を差し替える。<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
上記の用に変更したレイアウトファイルは下記の通り。
<!DOCTYPE html>
<html>
<head>
<title><%= yield(:title) %> | Ruby on Rails Tutorial Sample App</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all',
'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application',
'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
ここまででテストをパスしても、Html、Help、Aboutページの重複した箇所を修正する必要がある。
###HTML構造を削除したHomeページGREEN###
<% provide(:title, "Home") %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
###HTML構造を削除したHelpページGREEN###
<% provide(:title, "Help") %>
<h1>Help</h1>
<p>
Get help on the Ruby on Rails Tutorial at the
<a href="https://railstutorial.jp/help">Rails Tutorial help page</a>.
To get help on this sample app, see the
<a href="https://railstutorial.jp/#ebook"><em>Ruby on Rails Tutorial</em>
book</a>.
</p>
###HTML構造を削除したAboutページ###
<% provide(:title, "About") %>
<h1>About</h1>
<p>
<a href="https://railstutorial.jp/">Ruby on Rails Tutorial</a>
is a <a href="https://railstutorial.jp/#ebook">book</a> and
<a href="https://railstutorial.jp/screencast">screencast</a>
to teach web development with
<a href="https://rubyonrails.org/">Ruby on Rails</a>.
This is the sample application for the tutorial.
</p>
上のように定義されたビューは、Home、Help、Aboutページの表示は以前とは変わりませんが、コードの重複が大きく削減された。
GREEN
ubuntu:~/environment/sample_app (static-pages) $ rails test
Running via Spring preloader in process 10352
Started with run options --seed 16102
3/3: [=======================================================================================================] 100% Time: 00:00:01, Time: 00:00:01
Finished in 1.06917s
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
###演習###
1.サンプルアプリケーションにContact(問い合わせ先)ページを作成してください15 。(ヒント: まずはリスト 3.16を参考にして、/static_pages/contactというURLのページに「Contact | Ruby on Rails Tutorial Sample App」というタイトルが存在するかどうかを確認するテストを最初に作成しましょう。次に、3.3.3でAboutページを作ったときのと同じように、Contactページにもリスト 3.41のコンテンツを表示してみましょう。)
###Contactページで使うコード###
<% provide(:title, "Contact") %>
<h1>Contact</h1>
<p>
Contact the Ruby on Rails Tutorial about the sample app at the
<a href="https://railstutorial.jp/contact">contact page</a>.
</p>
回答
/sample_app/test/controllers/static_pages_controller_test.rbにContactページのテストを作成する。
test "should get contact" do
get static_pages_contact_url
assert_response :success
assert_select "title", "contact | #{@base_title}"
end
これだけだとコントローラーが無いとエラーが返る。
なのでコントローラにも追加。
/sample_app/app/controllers/static_pages_controller.rb
ここでtestしても同じことでした。なのでroutにもcontact追加。
Rails.application.routes.draw do
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
get 'static_pages/contact'
root 'application#hello'
end
ここでtestすると下記エラー
ERROR["test_should_get_contact", #<Minitest::Reporters::Suite:0x00005612791b5a58 @name="StaticPagesControllerTest">, 1.1499366540001574]
test_should_get_contact#StaticPagesControllerTest (1.15s)
ActionController::MissingExactTemplate: ActionController::MissingExactTemplate: StaticPagesController#contact is missing a template for request formats: text/html
test/controllers/static_pages_controller_test.rb:28:in `block in <class:StaticPagesControllerTest>'
MissingExactTemplate。Template=ビューファイルがない。なので作る
$ touch app/views/static_pages/contact.html.erb
できたcontactファイル内を上記の内容に編集する。
これでtestはGREENになる。
ubuntu:~/environment/sample_app (static-pages) $ rails test
Running via Spring preloader in process 11811
Started with run options --seed 60157
4/4: [====] 100% Time: 00:00:00, Time: 00:00:00
Finished in 0.98530s
4 tests, 8 assertions, 0 failures, 0 errors, 0 skips
###ルーティングの設定###
サイトのカスタマイズが終わって、テストスイートも軌道にのってきたのでアプリケーションルートのルーティングを設定しておく。ルーティングを設定するのはroutes.rbファイルを編集してルート「/」とWebページを結びつける。結びつける相手はHomeページ。
root 'application#hello
を次のコードに書き換える
root 'static_pages#home
###HomeページをルートURLに設定する###
Rails.application.routes.draw do
root 'static_pages#home'
get 'static_pages/home'
get 'static_pages/help'
get 'static_pages/about'
end
###演習###
1.リスト 3.42にrootルーティングを追加したことで、root_urlというRailsヘルパーが使えるようになりました(以前、static_pages_home_urlが使えるようになったときと同じです)。リスト 3.43のFILL_INと記された部分を置き換えて、rootルーティングのテストを書いてみてください。
回答
test "should get root" do
get root_url
assert_response :success
end
2.実はリスト 3.42のコードを書いていたので、先ほどの課題のテストは既に green になっているはずです。このような場合、テストを変更する前から成功していたのか、変更した後に成功するようになったのか、判断が難しいです。リスト 3.42のコードがテスト結果に影響を与えていることを確認するため、リスト 3.44のようにrootルーティングをコメントアウトして見て、 red になるかどうか確かめてみましょう(なおRubyのコメント機能については4.2で説明します)。最後に、コメントアウトした箇所を元に戻し(すなわちリスト 3.42に戻し)、テストが green になることを確認してみましょう。
回答 やってみたらTestは予想通りREDに
ERROR["test_should_get_root", #<Minitest::Reporters::Suite:0x00007f8ce89b5380 @name="StaticPagesControllerTest">, 0.020042755999838846]
test_should_get_root#StaticPagesControllerTest (0.02s)
NameError: NameError: undefined local variable or method `root_url' for #<StaticPagesControllerTest:0x00007f8ce8743f20>
test/controllers/static_pages_controller_test.rb:10:in `block in <class:StaticPagesControllerTest>'
###最後に###
$ git add -A
$ git commit -m "Finish static pages"
次にトピックブランチからmasterブランチに移動しマージする。
$ git checkout master
$ git merge static-pages
きりの良いところでコードをリモートリポジトリにアップロード。
git push
またHerokuにデプロイ
$ rails test
$ git push heroku
###本章のまとめ###
- テスト駆動開発では「RED・GREEN・REFACTER」サイクルを繰り返す、これが漸く理解できたかな。
###高度なセットアップ###
成功/失敗の表示設定をする「minitest reporters」とファイルの変更を検出して必要なテストだけを自動実行してくれる「Guard」の2つ。
このセットアップはmasterブランチで行う必要があるので切り替える。
$ git checkout master
###minitest reporters###
gemファイルにminitest-reportersを追加するとクラウドIDE(cloud9など)のシステムでREDやGREENの表示がみえやすくなる。
###テストでREDやGREENを表示できうるようにする###
ENV['RAILS_ENV'] ||= 'test'
require_relative '../config/environment'
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
# 特定のワーカーではテストをパラレル実行する
parallelize(workers: :number_of_processors)
# すべてのテストがアルファベット順に実行されるよう、
#test/fixtures/*.ymlにあるすべてのfixtureをセットアップする
fixtures :all
# (すべてのテストで使うその他のヘルパーメソッドは省略)
end
###Guardによるテストの自動化###
rails testコマンドを使うとき、テストをしようとするたびにエディタからコマンドラインに移動して手動でコマンドを打ち込むのが面倒なのでGuardを使って自動化を実行させるようにする。
Guardはファイルシステムの変更を監視し、例えばstatic_pages_test.rbファイルなどを変更すると自動的に実行してくれるツール。
実はすでにGemfileでguard gemをアプリケーション内にとりこんでいるのであとは初期化をするだけで動かすことができる。
ubuntu:~/environment/sample_app (master) $ bundle exec guard init
12:30:42 - INFO - Writing new Guardfile to /home/ubuntu/environment/sample_app/Guardfile
12:30:42 - INFO - minitest guard added to Guardfile, feel free to edit it
統合テストとビューが更新されたら自動的に適切なテストが実行されるように生成されたGuardfileを編集する。
###カスタマイズしたGuardfile###
# Guardのマッチング規則を定義
guard :minitest, spring: "bin/rails test", all_on_start: false do
watch(%r{^test/(.*)/?(.*)_test\.rb$})
watch('test/test_helper.rb') { 'test' }
watch('config/routes.rb') { interface_tests }
watch(%r{app/views/layouts/*}) { interface_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
# 与えられたリソースに対応する統合テストを返す
def integration_tests(resource = :all)
if resource == :all
Dir["test/integration/*"]
else
Dir["test/integration/#{resource}_*.rb"]
end
end
# インターフェースが該当するすべてのテストを返す
def interface_tests
integration_tests << "test/controllers/"
end
# 与えられたリソースに対応するコントローラのテストを返す
def controller_test(resource)
"test/controllers/#{resource}_controller_test.rb"
end
# 与えられたリソースに対応するすべてのテストを返す
def resource_tests(resource)
integration_tests(resource) << controller_test(resource)
end
クラウドIDEではもうひとつ手順が必要。次のややこしいコマンドを実行してプロジェクト内の全ファイルをGuardで監視できるようにする。
$ echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
$ sudo sysctl -p
Guardの設定が完了したら、新しいターミナルで次のコマンド実行する。
$ bundle exec guard
ubuntu:~/environment/sample_app (master) $ bundle exec guard
12:39:16 - INFO - Guard::Minitest 2.4.6 is running, with Minitest::Unit 5.11.3!
12:39:18 - INFO - Guard is now watching at '/home/ubuntu/environment/sample_app'
[1] guard(main)>
テストを変更ファイルだけでなく、フルで実行したい場合は、guard>プロンプトでReturnキーをおします。Guardを終了するにはCtrl+Dキーを押す。
はっきりしたした原因がないのにテストが失敗する場合は次のようにGuardをいったん終了し、Springを止めて再起動してみましょう。
$ bin/spring stop # テストが原因不明で動かなくなったら、このコマンドを実行してみる
$ bundle exec guard
ここまでで行動なセットアップは終了です。変更を忘れずにコミットしておく
$ git add -A
$ git commit -m "Complete advanced testing setup"