Ruby on Rails チュートリアル 実例を使ってRailsを学ぼう / Michael Hartl (マイケル・ハートル) を見ながらやったことを、あとでもう一度できるようにまとめます!!第三章!!
第三章の説明
- 静的ページを作成する
- テスト駆動開発をはじめる(RSpecの使い方がわかる)
- レイアウトファイルを使う
プロジェクトを作成 & 設定
$ cd ~/workspace/ruby/rails/
$ rails new sample_app --skip-test-unit
Gemfileを修正
新しくRSpecの為のGemとRSpecのライブラリのGemが追加されてる。
$ subl Gemfile
source 'https://rubygems.org'
ruby '2.0.0'
#ruby-gemset=railstutorial_rails_4_0
gem 'rails', '4.0.0'
group :development, :test do
gem 'sqlite3', '1.3.7'
gem 'rspec-rails', '2.13.1'
end
group :test do
gem 'selenium-webdriver', '2.0.0'
gem 'capybara', '2.1.0'
end
gem 'sass-rails', '4.0.0'
gem 'uglifier', '2.1.1'
gem 'coffee-rails', '4.0.0'
gem 'jquery-rails', '2.2.1'
gem 'turbolinks', '1.1.1'
gem 'jbuilder', '1.0.2'
group :doc do
gem 'sdoc', '0.3.20', require: false
end
group :production do
gem 'pg', '0.15.1'
gem 'rails_12factor', '0.0.2'
end
bundle インストール
$ bundle install --without production
$ bundle update
$ bundle install
秘密トークン初期化処理を動的に生成するように修正
ソースコードを公開する際、秘密トークンも一緒に公開することが無いように、
秘密トークンを動的に生成するようにする。
$ subl config/initializers/secret_token.rb
require 'securerandom'
def secure_token
token_file = Rails.root.join('.secret')
if File.exist?(token_file)
# Use the existing token.
File.read(token_file).chomp
else
# Generate a new token and store it in token_file.
token = SecureRandom.hex(64)
File.write(token_file, token)
token
end
end
SampleApp::Application.config.secret_key_base = secure_token
.gitignoreを修正
.secret に秘密トークンが記述されているので、公開リポジトリにpushしないように.gitignoreで無視するように指定している。
$ subl .gitignore
# Ignore bundler config.
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
# Ignore other unneeded files.
doc/
*.swp
*~
.project
.DS_Store
.idea
.secret
テストにRSpecを使う為の設定をする
$ rails generate rspec:install
Gitの設定
$ git init
$ git add .
$ git commit -m "Initial commit"
READMEを修正する
$ subl README.rdoc
$ git mv README.rdoc README.md
$ git commit -am "Improve the README"
Githubに公開する
$ git remote add origin https://github.com/yujiroarai/sample_app.git
$ git push -u origin master
herokuにデプロイ
$ heroku create
$ git push heroku master
$ heroku run rake db:migrate
静的ページを作成
トピックブランチを作る
$ git co -b static-pages
コントローラを生成する
$ rails generate controller StaticPages home help --no-test-framework
StaticPagesの部分がコントローラ名(ファイル名はスネークケースに変換される)。
home・helpはアクション名
--no-test-frameworkはRSpecのテストを生成しないからつけてる。
コマンドを間違えた場合は、rails destroyコマンドを使って元に戻す。
$ rails destroy controller StaticPages home help
git に commit
$ git add .
$ git commit -m "Add a StaticPages controller"
最初のテスト
テスト作成
$ rails generate integration_test static_pages
$ subl spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "StaticPages" do
describe "Home page" do
it "should have the content'SampleApp'" do
visit '/static_pages/home'
expect(page).to have_content('Sample App')
end
end
end
テストの設定を追加
$ subl spec/spec_helper.rb
RSpec.configure do |config|
.
.
.
+ config.include Capybara::DSL
end
テストを実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=>失敗する
コードを修正
$ subl app/views/static_pages/home.html.erb
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
テストを実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=>成功する
Helpページもテストする
$ subl spec/requests/static_pages_spec.rb
+ describe "Help page" do
+ it "should have the content 'Help'" do
+ visit '/static_pages/help'
+ expect(page).to have_content('Help')
+ end
+ end
テストを実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=>失敗する
コードを修正
$ subl app/views/static_pages/home.html.erb
<h1>Help</h1>
<p>
Get help on the Ruby on Rails Tutorial at the
<a href="http://railstutorial.org/help">Rails Tutorial help page</a>.
To get help on this sample app, see the
<a href="http://railstutorial.jp/book">Rails Tutorial book</a>.
</p>
テストを実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=>成功する
About Us ページを追加する
テストを修正して赤色にする
$ subl spec/requests/static_pages_spec.rb
+ describe "About page" do
+
+ it "should have the content 'About Us'" do
+ visit '/static_pages/about'
+ expect(page).to have_content('About Us')
+ end
+ end
テスト実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 失敗する
Failures:
1) StaticPages About page should have the content 'About Us'
Failure/Error: visit '/static_pages/about'
ActionController::RoutingError:
No route matches [GET] "/static_pages/about"
# ./spec/requests/static_pages_spec.rb:21:in `block (3 levels) in <top (required)>'
↓これは、/static_pages/aboutというルートをroutesファイルに追加する必要があるということを示している。
No route matches [GET] "/static_pages/about"
ルートを追加
$ subl config/routes.rb
SampleApp::Application.routes.draw do
get "static_pages/home"
get "static_pages/help"
+ get "static_pages/about"
.
.
.
end
テスト実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 失敗する
1) StaticPages About page should have the content 'About Us'
Failure/Error: visit '/static_pages/about'
AbstractController::ActionNotFound:
The action 'about' could not be found for StaticPagesController
# ./spec/requests/static_pages_spec.rb:21:in `block (3 levels) in <top (required)>'
↓これは、aboutアクションがStaticPagesControllerにないよ。って意味
The action 'about' could not be found for StaticPagesController
aboutアクションを追加
$ subl app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
+ def about
+ end
end
テスト実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 失敗する
1) StaticPages About page should have the content 'About Us'
Failure/Error: visit '/static_pages/about'
ActionView::MissingTemplate:
Missing template static_pages/about, application/about with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :raw, :ruby, :j builder, :coffee]}. Searched in:
* "/Users/yujiroarai/workspace/ruby/rails/sample_app/app/ views"
# ./spec/requests/static_pages_spec.rb:21:in `block (3 levels) in <top (required)>'
↓これは、テンプレートファイルが無いよって意味
Missing template static_pages/about
AboutUsのテンプレートファイル作成
$ touch app/views/static_pages/about.html.erb
$ subl app/views/static_pages/about.html.erb
<h1>About Us</h1>
<p>
The <a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
is a project to make a book and screencasts to teach web development
with <a href="http://rubyonrails.org/">Ruby on Rails</a>. This
is the sample application for the tutorial.
</p>
テスト実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 成功!!
少しだけ動的なページにする
タイトルを、「Ruby on Rails Tutorial Sample App」から「Ruby on Rails Tutorial Sample App | {ページ名}」に修正する。
タイトル変更をテストする
$ subl spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "StaticPages" do
describe "Home page" do
it "should have the content'SampleApp'" do
visit '/static_pages/home'
expect(page).to have_content('Sample App')
end
+ it "should have the right title" do
+ visit '/static_pages/home'
+ expect(page).to have_title("Ruby on Rails Tutorial Sample App | Home")
+ end
end
describe "Help page" do
it "should have the content 'Help'" do
visit '/static_pages/help'
expect(page).to have_content('Help')
end
+ it "should have the title 'Help'" do
+ visit '/static_pages/help'
+ expect(page).to have_title("Ruby on Rails Tutorial Sample App | Help")
+ end
end
describe "About page" do
it "should have the content 'About Us'" do
visit '/static_pages/about'
expect(page).to have_content('About Us')
end
+ it "should have the title 'About Us'" do
+ visit '/static_pages/about'
+ expect(page).to have_title("Ruby on Rails Tutorial Sample App | About Us")
+ end
end
end
テスト実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 失敗する
テストをパスするようにHTMLを修正する
レイアウトファイルを修正
共通のHTMLはレイアウト用のファイルに書く。
$ subl app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>Ruby on Rails Tutorial Sample App | <%= yield(:title) %></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>
Homeページを修正
変数titleにHomeと設定
$ subl 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://railstutorial.jp/">Ruby on Rails Tutorial</a>
sample application.
</p>
Helpページを修正
$ subl 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.org/help">Rails Tutorial help page</a>.
To get help on this sample app, see the
<a href="http://railstutorial.jp/book">Rails Tutorial book</a>.
</p>
Aboutページを修正
$ subl app/views/static_pages/about.html.erb
<% provide(:title, 'About Us') %>
<h1>About Us</h1>
<p>
The <a href="http://railstutorial.jp/">Ruby on Rails Tutorial</a>
is a project to make a book and screencasts to teach web development
with <a href="http://rubyonrails.org/">Ruby on Rails</a>. This
is the sample application for the tutorial.
</p>
テストを実行
$ bundle exec rspec spec/requests/static_pages_spec.rb
=> 成功!!
Githubにpush
$ git add .
$ git commit -m "Finish static pages"
$ git co master
$ git merge static-pages --no-ff
$ git push
herokuにデプロイ
$ git push heroku
演習: 問い合わせページを作成する
テスト作成
$ subl spec/requests/static_pages_spec.rb
+ describe "Contact page" do
+ it "should have the content 'Contact" do
+ visit '/static_pages/contact'
+ expect(page).to have_content('Contact')
+ end
+
+ it "should have the title 'Contact'" do
+ visit '/static_pages/contact'
+ expect(page).to have_title("Ruby on Rails Tutorial Sample App | Contact")
+ end
+ end
ルートを追加
$ subl config/routes.rb
SampleApp::Application.routes.draw do
get "static_pages/home"
get "static_pages/help"
get "static_pages/about"
+ get "static_pages/contact"
アクションを追加
$ subl app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
end
def help
end
def about
end
+ def contact
+ end
end
ビューを追加
$ touch app/views/static_pages/contact.html.erb
$ subl app/views/static_pages/contact.html.erb
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
Contact Ruby on Rails Tutorial about the sample app at the
<a href="http://railstutorial.jp/contact">contact page</a>.
</p>
テストをもっと簡単に使う為の設定
Guardによるテストの自動化
guard-rspecをGemfileに追加する。
$ subl Gemfile
group :development, :test do
gem 'sqlite3', '1.3.7'
gem 'rspec-rails', '2.13.1'
+ gem 'guard-rspec', '2.5.0'
end
bundle インストール
$ bundle install --without production
Guardを初期化し、RSpecと一緒に動作するようにする。
$ bundle exec guard init rspec
03:39:23 - INFO - Writing new Guardfile to /Users/yujiroarai/ workspace/ruby/rails/sample_app/Guardfile
03:39:23 - INFO - rspec guard added to Guardfile, feel free to edit it
Guardfileを修正する。
$ subl Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
+ require 'active_support/inflector'
guard 'rspec' do
Guardを起動する。
$ bundle exec guard
Sporkでテストを高速化
Gemfileを修正
$ subl Gemfile
group :development, :test do
gem 'sqlite3', '1.3.7'
gem 'rspec-rails', '2.13.1'
gem 'guard-rspec', '2.5.0'
+ gem 'spork-rails', github: 'sporkrb/spork-rails'
+ gem 'guard-spork', '1.5.0'
+ gem 'childprocess', '0.3.6'
end
bundle インストール
$ bundle install
sporkの設定にbootstrapを指定。(TODOなにしてるかわからないから調べる)
$ bundle exec spork --bootstrap
環境の読み込みを一回で済ますため、spec/spec_helper.rbの中で環境をpreforkのブロックで読み込むように、RSpecの設定を変更する。
Spork.prefork doの中に設定を追加する。
Spork.prefork do
# Loading more in this block will cause your tests to run faster. However,
# if you change any configuration or code from libraries loaded here, you'll
# need to restart spork for it take effect.
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}
# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)
RSpec.configure do |config|
# == Mock Framework
#
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
#
# config.mock_with :mocha
# config.mock_with :flexmock
# config.mock_with :rr
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# If true, the base class of anonymous controllers will be inferred
# automatically. This will be the default behavior in future versions of
# rspec-rails.
config.infer_base_class_for_anonymous_controllers = false
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = "random"
config.include Capybara::DSL
end
end
GuardにSporkを導入する
GuardのファイルにSporkの設定を導入
$ bundle exec guard init spork
$ subl
require 'active_support/inflector'
guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' },
:rspec_env => { 'RAILS_ENV' => 'test' } do
watch('config/application.rb')
watch('config/environment.rb')
watch('config/environments/test.rb')
watch(%r{^config/initializers/.+\.rb$})
watch('Gemfile')
watch('Gemfile.lock')
watch('spec/spec_helper.rb') { :rspec }
watch('test/test_helper.rb') { :test_unit }
watch(%r{features/support/}) { :cucumber }
end
guard 'rspec', after_all_pass: false, cli: '--drb' do
.
.
.
end
GuardとSporkを同時に起動する
$ bundle exec guard