あとでもっかい試す用 - Ruby on Rails 4.0 チュートリアル - 第三章


[Ruby on Rails チュートリアル 実例を使ってRailsを学ぼう / Michael Hartl (マイケル・ハートル)](http://railstutorial.jp/chapters/static-pages?version=4.0#sec-adding_a_page) を見ながらやったことを、あとでもう一度できるようにまとめます！！第三章！！

# 第三章の説明

- 静的ページを作成する
- テスト駆動開発をはじめる（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