[Ruby入門 Rails5編] 04. コントローラの作成とテスト


前回は、MVCの全体像を、引きのショットでざっくり眺めてみた。
今回はMVCの肝となるコントローラを作成する手順を学ぶ。
あと、コントローラに対するテストも書いてみる。


### 【１】準備
---

いままで何度かやった手順なのでざっと〜。

① アプリケーションの作成

```bash
cd /docker-host/share/webapps/

rails _5.1.1_ new sample_app
```

　
② Gemを追加

```bash
# Gemfileを開く
cd /docker-host/share/webapps/sample_app
vi Gemfile

# 以下を追記
group :test do
  gem 'rails-controller-testing'
  gem 'minitest-reporters'
  gem 'guard'
  gem 'guard-minitest'
end

# あとgem取得先のURLをhttpに変更
source 'https://rubygems.org'
↓
source 'http://rubygems.org'

# んでインストール
bundle install --path vendor/bundle
```

　
③ gitにコミット
git add .
git commit -m "sample_app作成"

　
④ とりあえず動作確認

```bash
# Puma起動。「rails s」は「rails server」の短縮形
$ rails s
=> Booting Puma
〜 中略 〜
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

# んで、ブラウザから以下でアクセスできればOK
http://localhost:3000/

# 確認できたら、Pumaはいったん停止する（ Ctrl-C ）
```

　
### 【２】コントローラを生成する
---

「rails generate 〜」で、コントローラを生成してみる。

　
① コントローラの生成

```bash
cd /docker-host/share/webapps/sample_app

# 「StaticPages」コントローラを作って "home" と "help" というアクションを定義
rails generate controller StaticPages home help

# 何がつくられたか
$ git status -s
 M config/routes.rb
?? app/assets/javascripts/static_pages.coffee
?? app/assets/stylesheets/static_pages.scss
?? app/controllers/static_pages_controller.rb
?? app/helpers/static_pages_helper.rb
?? app/views/static_pages/
?? test/controllers/static_pages_controller_test.rb

# views/* の下には何がつくられたか
$ ls -1 app/views/static_pages/
help.html.erb
home.html.erb


# gitにコミット
git add .
git commit -m "StaticPagesコントローラを生成"
```

生成されるファイルは、前回のscaffoldの生成物から、モデルやDB関連を除いたもの、となっているようだ。
・コントローラ
・ビュー
・ヘルパー
・JSやCSSなどのassets関連
・テスト関連

また、scaffold のときと同様に、ルーティング設定ファイル「 config/routes.rb 」も編集されている。

　
② 表示確認

```bash
# Puma起動
$ rails s
=> Booting Puma
〜 中略 〜
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop

# んで、ブラウザから以下のURLにアクセスできればOK
http://localhost:3000/static_pages/home
http://localhost:3000/static_pages/help

# 確認できたら、Pumaはいったん停止する（ Ctrl-C ）
```

　
#### [補足] generate したけど取り消したい

```
rails generate controller StaticPages home help
↓に対して...
rails destroy  controller StaticPages home help

rails generate model User name:string email:string
↓に対して...
rails destroy model User

など。
```

　
### 【３】ルーティングの設定を確認する
---

「 config/routes.rb 」

```ruby
Rails.application.routes.draw do
  get 'static_pages/home'

  get 'static_pages/help'

  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
```

上記は、getメソッドで static_pages/xxx というURLにアクセスすると、StaticPages コントローラのxxxアクションを実行するよ〜、という設定。


　
### 【４】コントローラのソースを確認する
---

「app/controllers/static_pages_controller.rb」

```ruby
class StaticPagesController < ApplicationController
  def home
  end

  def help
  end
end
```

「rails generate 〜」で指定したアクションのメソッドが定義されている。
命名規則で紐付いたビューを表示するだけなので、処理は何も記述されていない。

　
### 【５】ビューのソースを確認する
---

「app/views/static_pages/home.html.erb」
「app/views/static_pages/help.html.erb」

```ruby
<h1>StaticPages#home</h1>
<p>Find me in app/views/static_pages/home.html.erb</p>
```

今回は特になにも書いてないな...

「 app/views/コントローラ名のスネークケース/アクション名.html.erb 」
という命名規則に従うことで、コントローラのアクションと紐付いているというところがポイントかな。

　
### 【６】コントローラのテストを書いてみる
---

scaffold や generate の結果確認で見たように、Rails ではデフォルトのソース群に既にテスト用のリソースが含まれている。
なので、面倒な導入なしにいきなりテストを書ける。

　
#### [準備] テストの出力をかっこよくする（任意）

さきの手順でプロジェクトに追加済みの minitest reporters というGemを有効にすると、テストの結果出力が綺麗になってちょっとテンション上がる。
以下のファイルにGemを利用するように記述する。

「test/test_helper.rb」

```ruby
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'

# ↓この2行を追加
require "minitest/reporters"
Minitest::Reporters.use!

class ActiveSupport::TestCase
〜 中略 〜
end
```

　
① どんなテストが生成されているのか確認する

コントローラとセットで生成されたテストコードの、デフォルトの状態は以下。

「test/controllers/static_pages_controller_test.rb」

```ruby
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
```

各アクションに対してテストが定義されていて、そのアクションのURLに対してGETでアクセスし、結果が :success（HTTPレスポンス200）かどうかをテストしている。
文法的には、test メソッドに 引数 と ブロックを渡しているのかな。

この段階でいっかいテストを実行してみると、以下のように何事もなく成功する。
※Pumaの起動は必要ない。かわりに Spring というサーバーを起動して実行するので、少し時間がかかる。

```bash
$ rails test
Running via Spring preloader in process 517
〜 中略 〜
Started with run options --seed 15128

  2/2: [=============================] 100% Time: 00:00:14, Time: 00:00:14

Finished in 14.31579s
2 tests, 2 assertions, 0 failures, 0 errors, 0 skips
```

　
② これからコントローラに実装する機能に対するテストを先に書いて失敗させてみる

いわゆるテストファーストというやつ。
ここでは、新規に about というアクションを追加する想定で、先にテストコードを書いてみる。

「test/controllers/static_pages_controller_test.rb」

```ruby
require 'test_helper'

class StaticPagesControllerTest < ActionDispatch::IntegrationTest

  〜 中略 〜

  # about アクションへのGETが成功するか
  test "should get about" do
    get static_pages_about_url
    assert_response :success
  end

end
```

んで、テストを実行して、失敗することを確認しておく。

```bash
$ rails test
Running via Spring preloader in process 611
〜 中略 〜
ERROR["test_should_get_about", StaticPagesControllerTest, 14.417123627001274]
〜 中略 〜
NameError:         NameError: undefined local variable or method `static_pages_about_url' for #<StaticPagesControllerTest:0x0055be52dfee48>
            test/controllers/static_pages_controller_test.rb:15:in `block in <class:StaticPagesControllerTest>'
〜 中略 〜
3 tests, 2 assertions, 0 failures, 1 errors, 0 skips
```

　
③ about アクションを追加する

③-a コントローラにアクションを追加

「app/controllers/static_pages_controller.rb」

```ruby
# これを追加
def about
end
```
　
③-b ルーティング設定を追加

「config/routes.rb」

```ruby
# これを追加
get 'static_pages/about'
```

　
③-c ビューを新規作成

「app/views/static_pages/about.html.erb」

```ruby
<% # とりあえずこんな内容で作成 %>
<h1>StaticPages#about</h1>
<p>This is `about` page!</p>
```
 
　
④ んで、再度テストしてみる

```bash
$ rails test
〜 中略 〜
3 tests, 3 assertions, 0 failures, 0 errors, 0 skips
```

通った！


今回はなんか簡単でしたが、ひとまず コントローラの作成とテストについて学ぶことができた。
コントローラの詳細については回を追って順次学んでいく想定。
今日はここまで！