Controller spec基本 - parameterとルーティングエラーについて

RSpec コントローラースペックを書いていて、```ActionController::UrlGenerationError: No route matches``` みたいなエラーが発生した場合の回避方法。

## はじめに

### コントローラスペックの基本構文

例：

```
let(:params) { { contact: FactoryGirl.attributes_for(:contact) } }
post :create, params
```

- HTTPメソッド(post)
- コントローラメソッド(:create)
- メソッドに渡すパラメータ(params) 任意

#### パラメータに関する注意点

```rake routes``` で確認出来るpathに含まれるパラメータや、POST時のbodyに含まれるもの全てをメソッドに渡すパラメータ(params)にHashで渡す。

nested resourcesやconcernsでresourceをネストさせた場合は、親resource_idなども含まれる。

例：アクセスしたいControllerのroutesが

```message_comments GET /messages/:message_id/comments(.:format) comments#index```

みたいな感じだったら

```
let(:params) { { message_id: 101 } }
get :index, params
```

でアクセスできる。
pathに含まれるparameterが足りない場合、こんなエラーが発生する。

発生するエラー

```
ActionController::UrlGenerationError: No route matches {:action=>"index", :controller=>"messages_controller"}
```

- - -

ネストしてるリソースの書き方例を細かめに。

### nested resource テスト記載例
#### config/routes.rb

```config/routes.rb
concern :commentable do
  resources :comments
end

resources :messages, concerns: :commentable
```

##### ```./bin/rake routes```
生成されるroutes (commentable部分のみ)

```
    message_comments GET    /messages/:message_id/comments(.:format)          comments#index
                     POST   /messages/:message_id/comments(.:format)          comments#create
 new_message_comment GET    /messages/:message_id/comments/new(.:format)      comments#new
edit_message_comment GET    /messages/:message_id/comments/:id/edit(.:format) comments#edit
     message_comment GET    /messages/:message_id/comments/:id(.:format)      comments#show
                     PATCH  /messages/:message_id/comments/:id(.:format)      comments#update
                     PUT    /messages/:message_id/comments/:id(.:format)      comments#update
                     DELETE /messages/:message_id/comments/:id(.:format)      comments#destroy
```

こんなコントローラーを・・

```app/controllers/comments_controller.rb
class CommentsController < ApplicationController
  def new
  end

  def create
    # TODO : save
  end
  
  def update
    # TODO : save
  end
  
  # ... 省略
  
  private
  
  def comment_params
    params.require(:comment).permit(:content)
  end
end
```

RSpecでテスト・・・

```specs/controllers/comments_controller_spec.rb
require 'rails_helper'

RSpec.describe CommentsController, type: :controller do
  describe "GET #new" do
    subject { get :new, params }
    let(:params) { { message_id: 100 } }
    it { is_expected.to be_success }
  end
  
  describe "POST #create" do
    subject { post :create, params }
    let(:params) do
      { 
        message_id: 100,
        comment: {
          content: 'Test message comment'
        }
      }
    end
    it { is_expected.to be_success }
  end
  
  describe "PATCH #update" do
    subject { patch :update, params }
    let(:params) do
      { 
        id: 1,
        message_id: 100,
        comment: {
          content: 'Test message comment'
        }
      }
    end
    it { is_expected.to be_success }
  end
end
```

## 参考
- [RSpec で subject & expect する時の注意点 - Qiita](http://qiita.com/mm36/items/453d71d48dd8f462344c)
- [2.8 ルーティングの「concern」機能](http://railsguides.jp/routing.html#%E3%83%AB%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E3%80%8Cconcern%E3%80%8D%E6%A9%9F%E8%83%BD)