Rspec-rails: ActionController::RoutingError: No route matches [...]

Created on 11 Jan 2013  ·  36Comments  ·  Source: rspec/rspec-rails

I'm writting an API for a pet project of mine and was running rails 3.2.9
I decided to update rails in order to avoid security problems but I suddenly ran into some problems.

I've been able to resolve most of them but I keep getting this and don't know what to do with it.

I am using RSPEC to test a json API and until this upgrade everything was going just fine and all routes were working perfectly.

I'm not sure wether it's a bug or a bad usage from me, so I'm sorry if it's the former.
Here is my code :

Routes :

Fake::Application.routes.draw do
    namespace :api do
        namespace :v1 do
            scope '/user' do
                match "signup" => "registrations#create", :via => :post
                match "delete" => "registrations#destroy", :via => :delete

                match "login"  => "sessions#create", :via => :post
                match "logout" => "sessions#destroy", :via => :delete
            end
        end
    end
end

Spec :

require 'spec_helper'

describe Api::V1::SessionsController do
    before do
        @user = {
            :email => Faker::Internet::email,
            :pseudo => Faker::Internet::user_name,
            :password => Faker::Lorem::words(2).join
        }
        user = User.create @user
    end

    context 'should login in' do

        it 'should be ok ' do
            post '/api/v1/user/login', :user => @user
            JSON.parse(response.body)["success"].should == true
        end

        it 'should fail without credentials' do
            post '/api/v1/user/login', {}
            JSON.parse(response.body)["success"].should == false
        end
    end
end

And the result :

± rspec spec/controllers/sessions_controller_spec.rb                                                                                                                    5:21:10 PM
Rack::File headers parameter replaces cache_control after Rack 1.5.
FF

Failures:

  1) Api::V1::SessionsController should login in should be ok with auth_token
     Failure/Error: post '/api/v1/user/login', :user => @user
     ActionController::RoutingError:
       No route matches {:user=>{:email=>"[email protected]", :pseudo=>"linwood_gislason", :password=>"repellendusaliquid"}, :controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
     # ./spec/controllers/sessions_controller_spec.rb:17:in `block (3 levels) in <top (required)>'

  2) Api::V1::SessionsController should login in should fail without credentials
     Failure/Error: post '/api/v1/user/login', {}
     ActionController::RoutingError:
       No route matches {:controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
     # ./spec/controllers/sessions_controller_spec.rb:22:in `block (3 levels) in <top (required)>'

Finished in 0.50905 seconds
2 examples, 2 failures

Failed examples:

rspec ./spec/controllers/sessions_controller_spec.rb:15 # Api::V1::SessionsController should login in should be ok with auth_token
rspec ./spec/controllers/sessions_controller_spec.rb:21 # Api::V1::SessionsController should login in should fail without credentials

Edit :

Rails version : 3.2.11
Rspec version : 2.12.2
Ruby version : ruby 1.9.3p0

Most helpful comment

I find it weird that rspec-mocks is not 2.12.2 but 2.12.1 but well...

That is quite intentional. We don't want to have to release the whole suite to do patch releases on each gem, so the rspec gem depends on "rspec-xxx", "~> 2.12.0" where xxx is replaced by each of "core", "expectations", and "mocks": https://github.com/rspec/rspec/blob/master/rspec.gemspec#L31

In this case, 2.12.1 is the latest 2.12 release of rspec-core and rspec-mocks, whereas 2.12.2 is the latest release of rspec-expectations. Make sense?

All 36 comments

Did you also upgrade rspec or rspec-rails? If so, from what version to what version (rspec-rails only just released 2.12.2)?

I did a global update of my gems on my system and updated the Gemfile.lock with "bundle update".

It is using rspec-rails 2.12.2 and rspec 2.12.2

below is an excerpt of my Gemfile.lock

 rspec-core (2.12.2)
    rspec-expectations (2.12.1)
      diff-lcs (~> 1.1.3)
    rspec-mocks (2.12.1)
    rspec-rails (2.12.2)
      actionpack (>= 3.0)
      activesupport (>= 3.0)
      railties (>= 3.0)
      rspec-core (~> 2.12.0)
      rspec-expectations (~> 2.12.0)
      rspec-mocks (~> 2.12.0)

I find it weird that rspec-mocks is not 2.12.2 but 2.12.1 but well...

I find it weird that rspec-mocks is not 2.12.2 but 2.12.1 but well...

That is quite intentional. We don't want to have to release the whole suite to do patch releases on each gem, so the rspec gem depends on "rspec-xxx", "~> 2.12.0" where xxx is replaced by each of "core", "expectations", and "mocks": https://github.com/rspec/rspec/blob/master/rspec.gemspec#L31

In this case, 2.12.1 is the latest 2.12 release of rspec-core and rspec-mocks, whereas 2.12.2 is the latest release of rspec-expectations. Make sense?

BTW you can see that expressed in the last 3 lines of the part of Gemfile.lock you posted above:

rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0)
rspec-mocks (~> 2.12.0)

Makes sense :)
Thanks

@Shahor were you able to find a workaround for this issue? I'm having the exact same problem.

@rafael It's a spare project and I didn't have much time this week so I didn't really dig.
Plus I'm "fairly new" to testing so I really don't know where to check for a solution =/

I don't know how to resolve this. If you have any idea feel free to comment again :)

I'm upping this since I have no idea what to do on the matter :(

Anyone has an idea/suggestion about how to make this work ? I don't know where to start looking at.

I am experiencing the same issue. I upgraded Rails version, along with rspec and rspec-rails. Now most of my controller tests fail with ActionController::RoutingError.

The application continues to work as expected though.

Yup, I would happily fix this if I knew where to start from :)

Well. My problem turned out to be with nested controllers and the change between journey 1.0.3 and 1.0.4.

The following works through the app, but would raise ActionController::RoutingError in a test:

resources :payments, only: [:index] do
  resources :payment_policies, only: [:index], controller: "Payments::PaymentPolicies"
end

But replacing it with:

resources :payments, only: [:index] do
  resources :payment_policies, only: [:index], controller: "payments/payment_policies"
end

Or:

resources :payments, only: [:index] do
  resources :payment_policies, only: [:index], module: :payments
end

Fixes the problem. I'm not entirely sure where I should report a bug. Perhaps the controller syntax I was using is deprecated. But it may have broken. @alindeman have any input?

FYI that code is copied out of a proof of concept rails app available here:

https://github.com/kmcphillips/rspec_rails_routing_error_example

I don't really know if this is a bug I should report somewhere, or if that routing syntax was just working incidentally.

I tend to think it's a bug since my router doesn't really look like yours and is still not working =/
I can't find a way to rewrite it to make it work actually.

MyApp::Application.routes.draw do
    namespace :api do
        namespace :v1 do
            # user stuff
            scope '/user' do
                match "signup" => "registrations#create", :via => :post
                match "delete" => "registrations#destroy", :via => :delete

                match "login"  => "sessions#create", :via => :post
                match "logout" => "sessions#destroy", :via => :delete
            end
        end
    end
end

(thanks for the update :+1: )

You're spec is in the context of Api::V1::SessionsController so you just have to call the correct action :

context 'should login in' do

        it 'should be ok ' do
            post :create, {}
            JSON.parse(response.body)["success"].should == true
        end

        it 'should fail without credentials' do
            post :create, {}
            JSON.parse(response.body)["success"].should == false
        end
end

For me it works.

It would probably work, yup, but since it's an API and it should respond on http queries I'd like to test it like I would use it. Using the action directly wouldn't replicate the environment it will be used in.

So, try something like this :

spec/requests/api/v1/registrations_controller_spec.rb

require 'spec_helper'

describe Api::V1::RegistrationsController do
    before do
      @user = {
          :email => Faker::Internet::email,
          :pseudo => Faker::Internet::user_name,
          :password => Faker::Lorem::words(2).join
      }
      #user = User.create @user
    end

    context 'should login in' do

        it 'should be ok ' do
            post api_v1_login_path, {}
            JSON.parse(response.body)["success"].should == true
        end

        it 'should fail without credentials' do
            post api_v1_login_path, {}
            JSON.parse(response.body)["success"].should == false
        end
    end
end

I think this is a solution.
Because you want try if a request give you what you want, you don't want to test the Api::V1::RegistrationsController methods.

So may be rspec-rails acting in different way depending on your folders.

Nice try, but not working =/

3) Api::V1::SessionsController should login in should be ok with auth_token
     Failure/Error: post api_v1_login_path, :user => @user
     ActionController::RoutingError:
       No route matches {:user=>{:email=>"[email protected]", :pseudo=>"cordelia_mayer", :password=>"laborenisi"}, :controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
     # ./spec/controllers/sessions_controller_spec.rb:17:in `block (3 levels) in <top (required)>'

You didn't create the spec file in the right place, I still see the same error.
For me this is what I get :

rspec spec/requests/api_v1_spec.rb
  1) Api::V1::SessionsController should login in should be ok 
     Failure/Error: post api_v1_login_path, {}
     ActionView::MissingTemplate:
       Missing template api/v1/sessions/create, application/create with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee]}. Searched in:
         * "/Users/aweaoftheworld/Desktop/test_app/app/views"
     # ./spec/requests/api_v1_spec.rb:16:in `block (3 levels) in <top (required)>'

Because I didn't doo anything in my controller except creating the methods.

And this what I get when running:

rspec spec/controllers/api/v1/sessions_controller_spec.rb
  1) Api::V1::SessionsController should login in should be ok 
     Failure/Error: post api_v1_login_path, {}
     ActionController::RoutingError:
       No route matches {:controller=>"api/v1/sessions", :action=>"/api/v1/user/login"}
     # ./spec/controllers/api/v1/sessions_controller_spec.rb:16:in `block (3 levels) in <top (required)>'

Hum... not sure what you mean by that.
Here's my directory structure :
structure

Just try to move your spec into the file spec/requests/api_1_spec.rb and run it.
I didn't find why but rspec acting differently depending on the directory.

Ok thanks, it's working as expected.

I don't understand it though, why is it working under this repertory and not under the classic "controllers" (as it was before the rails update that broke everything) ? Can't find any ressource on that.

I'll go with this for now, but this is weird :/

Thanks

@Shahor Yeah this is really weird, didn't find anything about it too :s

Hey same here.

It does work on requests and not on controllers, but shouldn't this class be in controllers?

With controller specs, you use get :index (for example), not get foos_path. Controller specs don't run through the entire stack.

I understand that, but in my case I have the routing tester which tests that url /v1/users/create maps to v1/users#create. Which works.

And the test for controller is telling me that controller: "v1/users" action: "create doesn't exist", but it does. The same URL in requests does work. That's what weird for me.

And the test for controller is telling me that controller: "v1/users" action: "create doesn't exist", but it does. The same URL in requests does work. That's what weird for me.

If you post a small app I can pull down, I'll take a look.

Sure :)

In /spec/routing/v1/users_routing_spec.rb

require "spec_helper"

describe V1::UsersController do
  describe "routing" do

    it "routes to #create" do
      post("v1/users").should route_to("v1/users#create")
    end

  end
end

Then, this WORKS in /spec/requests/v1_users_controller_spec.rb. Note the post v1_users_path

require 'spec_helper'

describe V1::UsersController do

  describe "POST create" do
    describe "with valid emails params" do
      it "creates a new User" do
        expect {
          post v1_users_path, :user => valid_attributes, :format => :json
        }.to change(User, :count).by(1)
      end
end

This doesn't work in /spec/controllers/v1/users_controller_spec.rb.

returns RoutingError controller: "v1/users", action: "create", user: "{email: "[email protected]", password: "123456"}"
require 'spec_helper'

describe V1::UsersController do

  describe "POST create" do
    describe "with valid emails params" do
      it "creates a new User" do
        expect {
          post :create , :user => valid_attributes, :format => :json
        }.to change(User, :count).by(1)
      end
end

I'm not sure this is the problem, but since I see this and it _might_ be related: you can't really simulate sending JSON at a controller spec.

What if you run this instead in the controller spec?

post :create, :user => { :email => "[email protected]", :password => "123456" }

I know this is a pretty old and closed issue but I am still having this problem currently with Rails 4.1 and Rspec 2.14. My situation is very similar but not exactly the same and I am not sure how the solution or workarounds specified here apply to me.

I request the repo owners / admins to re-open this issue (or ask me to create a new one - whichever you find fit) based on the sample code below :

Here are the gems I am using :

    rspec (2.14.1)
      rspec-core (~> 2.14.0)
      rspec-expectations (~> 2.14.0)
      rspec-mocks (~> 2.14.0)
    rspec-core (2.14.8)
    rspec-expectations (2.14.5)
      diff-lcs (>= 1.1.3, < 2.0)
    rspec-mocks (2.14.6)
    rspec-rails (2.14.2)
      actionpack (>= 3.0)
      activemodel (>= 3.0)
      activesupport (>= 3.0)
      railties (>= 3.0)
      rspec-core (~> 2.14.0)
      rspec-expectations (~> 2.14.0)
      rspec-mocks (~> 2.14.0)

My routes definition :

  scope 'api/:version' do
    scope 'utils' do
      get 'valid_event' => 'utils#valid_event'
    end
  end

Please note that it is a scope unlike the previous code snippets which use a namespace. So my controller lives at the usual location app/controller/utils_controller.rb

The output of rake routes

valid_event GET    /api/:version/utils/valid_event(.:format)          utils#valid_event

My controller spec

require 'spec_helper'

describe UtilsController do

  describe 'valid_event' do

    it 'should return false if org_id param is missing' do
      get :valid_event, app_id: '123456', format: :json
      response_hash = JSON.parse(response.body)
      expect(response_hash['valid']).to be_false
    end

   # And 5 more example - all of which fail like the above one.
  end
end

And when I run the specs I get this error :

    UtilsController valid_event should return false if org_id param is missing
     Failure/Error: get :valid_event, app_id: '123456', format: :json
     ActionController::UrlGenerationError:
       No route matches {:action=>"valid_event", :app_id=>"123456", :controller=>"utils", :format=>:json}
     # ./spec/controllers/utils_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
     # -e:1:in `<main>'

The controller code itself works just fine. It is only the specs that fail.

What am I missing?

Further to the above mentioned details if I change the routes definition to any of the following the specs pass without any change anywhere else.

scope 'utils' do
  get 'valid_event' => 'utils#valid_event'
end
get 'valid_event' => 'utils#valid_event'

It's only with nested scoped routes that the tests are failing.

@sriranggd can you please open a new issue for this. I just tried with RSpec 3 and Rails 4 and I didn't have any problems. If possible, please setup a new sample repository which demonstrates the issue, trying to keep it as minimal as possible.

Eh stale page, I see you did that. Thanks

I'm currently still experiencing this issue. We even used the defined path only to get the No route matches {:controller=>"foo", :action=>"bar"} even when it's defined and being used appropriately. This issue needs to be looked at further.

@moultonBLiNQ please open a new issue, providing your steps to reproduce, or if possible the repository where the issue is happening. Be sure to include your routes, controller, a single simple failing spec, Ruby version, Rails version, and RSpec versions.

Is there any progress on this? It's been more than two years and this issue keeps coming up several times. I'm not even sure if this is a Rails issue or Rspec's.

It's a closed issue so no. Routing errors and behaviour in different spec types are mostly a Rails issue, if you can replicate an issue in RSpec without the equivalent minitest also breaking feel free to open a new issue with that reproduction :)

Was this page helpful?
0 / 5 - 0 ratings