問題
createアクションでメッセージを保存した時に、データベースのレコードが一つ増えているかどうかを検証するテストでNo route mathesエラーが出る。
コード
messagesコントローラー
def create
@message = Message.new(create_params)
if @message.save
redirect_to group_messages_path(@group)
else
@groups = current_user.groups.includes(:users)
@messages = Message.where(group_id: params[:group_id]).order(created_at: :ASC).includes(:user)
flash.now[:alert] = "メッセージが送信できませんでした。"
render action: :index
end
end
最初のコード
〜略〜
it "データベースに新しいメッセージが登録されること" do
expect{
post :create, message: attributes_for(:message, group_id: group.id )
}.to change(Message, :count).by(1)
end
〜略〜
これでテストしてみると以下のようなエラー文が!
(messageモデルはテキスト本文であるbodyというカラムがあり、FactoryGirlで定義しています)
Failures:
1) MessagesController POST #create メッセージの保存に成功した場合 データベースに新しいメッセージが登録されること
Failure/Error: post :create, message: attributes_for(:message, group_id: group.id )
ActionController::UrlGenerationError:
No route matches {:action=>"create", :controller=>"messages", :message=>{:body=>"Hello", :group_id=>81}}
# ./spec/controllers/messages_controller_spec.rb:34:in `block (5 levels) in <top (required)>'
# ./spec/controllers/messages_controller_spec.rb:33:in `block (4 levels) in <top (required)>'
Finished in 0.81058 seconds (files took 3.76 seconds to load)
4 examples, 1 failure
Failed examples:
rspec ./spec/controllers/messages_controller_spec.rb:32 # MessagesController POST #create メッセージの保存に成功した場合 データベースに新しいメッセージが登録されること
routeがいかれていると…。
binding.pryでparamsを確認してみると。
[1] pry(#<MessagesController>)> params
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"sQeDsqZbUxrIrnHiW82gSPb3rOAqvgyrDdM2DdGdI2nWrIMCAyYS5+ZEi0vhFrBV1nLBQJFNBp6WwwhsMrbdxw==", "message"=>{"body"=>"あら"}, "commit"=>"Send", "controller"=>"messages", "action"=>"create", "group_id"=>"1"} permitted: false>
思ったよりbodyが深く埋め込まれてました。
つまり、今現在のテストでは、
params: {:action=>"create", :controller=>"messages", :message=>{:body=>"Hello", :group_id=>81}}
こんなハッシュになっているところを
params: {:action=>"create", :controller=>"messages", :message=>{:body=>"Hello"}, :group_id=>81}
というふうにすればrouteがいい感じになるのではという仮説のもと、いろいろ試行錯誤してみたところ、以下のコードでテストをパスしました。
it "データベースに新しいメッセージが登録されること" do
expect{
post :create, params: { message: attributes_for(:message, { body: 'hello' }), group_id: group.id }
}.to change(Message, :count).by(1)
end
it内ではなくて、messageのFactorygirlで定義しようとも思ったのですが、うまくできませんでしたね。