RSpec on Rails で redirect_to のテストを書いていると、
ActionController::MethodNotAllowed Only get requests are allowed.
や
ActionController::MethodNotAllowed Only get, put, and delete requests are allowed.
といった、謎の例外が発生することがあります。
簡単な (無意味な) Rails アプリを作りながら、説明します。
$ rails hoge $ cd hoge $ cd vendor/plugins $ git clone git://github.com/dchelimsky/rspec.git $ git clone git://github.com/dchelimsky/rspec-rails.git $ rm -rf rspec/.git $ rm -rf rspec-rails/.git $ cd ../../ $ script/generate rspec
config/routes.rb
ActionController::Routing::Routes.draw do |map| map.resources :blogs end
app/controllers/blogs_controller.rb
class BlogsController < ApplicationController def index redirect_to :action => :new end def new render :text => 'this is new' end end
script/server して http://localhost:3000/blogs をブラウザで開けば、問題なく new にリダイレクトします。
そこで、テストを書いてみます。
spec/controllers/blogs_controller_spec.rb
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe BlogsController, 'GET /blogs/index' do it 'は、blogs#new にリダイレクトすること' do get :index response.should redirect_to(:action => :new) end end
実行!
$ script/spec spec/controllers/blogs_controller_spec.rb F 1) ActionController::MethodNotAllowed in 'BlogsController GET /blogs/index は、blogs#new にリダイレクトすること' Only get, put, and delete requests are allowed. /Library/Ruby/Gems/1.8/gems/actionpack-2.1.1/lib/action_controller/routing/recognition_optimisation.rb:65:in `recognize_path' ./spec/controllers/blogs_controller_spec.rb:7: script/spec:5: Finished in 0.284136 seconds 1 example, 1 failure
・・・え?
ここで、spec ファイルの redirect_to(:action => :new) を名前付きルートで redirect_to(new_blog_url) と置き換えて
spec/controllers/blogs_controller_spec.rb
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper') describe BlogsController, 'GET /blogs/index' do it 'は、blogs#new にリダイレクトすること' do get :index response.should redirect_to(new_blog_url) end end
再度実行。
$ script/spec spec/controllers/blogs_controller_spec.rb . Finished in 0.177365 seconds 1 example, 0 failures
通った..
・・・どうやら、config/routes.rb の
map.connect ':controller/:action/:id' map.connect ':controller/:action/:id.:format'
を消して map.resources を使い、redirect_to マッチャでハッシュを引数にすると発生するようなんですが、それ以外でも発生するときがあって、正直よくわかりません。
とりあえずの解決策としては、上で示したように redirect_to マッチャで名前付きルートを使う、もしくは、
rspec-rails/lib/spec/rails/matchers/redirect_to.rb の Spec::Rails::Matchers::RedirectTo#path_hash で
ActionController::Routing::Routes.recognize_path path
となっている箇所を、
ActionController::Routing::Routes.recognize_path path, :method => :get
にすると、例外が発生しなくなります。
ActionController の redirect_to と、RSpec on Rails の redirect_to マッチャで、内部的に引数の扱い方が異なっているような気がして、そのへんが関係しているのかなー、と思ったりします。