After an upgrade from Rails 3.0 to 3.2.21 and RSpec from 2.14 to 3.1, my API routes (namespaced, see below) aren't working any more. Specifically, they appear in rake routes and work in the browser in development mode, but they cause "Route not found" exceptions in tests and I cannot get them recognized in the console (but this might be my ignorance... any help appreciated).
Other (non-namespaced) routes work fine.
Here are the route definitions:
namespace :api, path: '', defaults: { format: :json }, constraints: { format: :json, subdomain: 'api' } do
namespace :v1 do
resources :foos, only: [:index] do
post :bar, on: :collection
end
end
end
match '*path' => 'application#route_not_found' # default 404 route
Here is the rake routes output:
bar_api_v1_foo_index POST /v1/foo/bar(.:format) api/v1/foo#bar {:format=>:json, :subdomain=>"api"}
api_v1_foo DELETE /v1/foo/:id(.:format) api/v1/foo#destroy {:format=>:json, :subdomain=>"api"}
Here is my spec (in spec/integration/api_v1_foo_controller_spec.rb):
require "spec_helper"
describe Api::V1::FooController do
before do
host! "api.#{host}" # set subdomain, see http://elia.schito.me/2011/09/15/set-subdomain-in-rails-3-request-specs/
end
describe "POST" do
it "should bar" do
post "/v1/foo/bar"
end
end
end
Here is the spec output:
Failures:
1) Api::V1::FooController POST should bar
Failure/Error: post "/v1/foo/bar"
ActionController::RoutingError:
No route matches [POST] "/v1/foo/bar"
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call'
# /opt/local/lib/ruby2.1/gems/2.1.0/gems/actionpack-3.2.21/lib/action_dispatch/middleware/show_exceptions.rb:56:in `call'
My feeble attempts at getting the routes to work in the console also fail, but for all Rails versions. It's probably the syntax (how do you use this?).
Rails.application.routes.recognize_path '/v1/foo/bar', method: :post, subdomain: 'api', format: :json
=> {:controller=>"application", :action=>"route_not_found", :path=>"v1/foo/bar"}
Why does the test above fail after the upgrade to Rails 3.2 and Rspec 3.1?
Update
This is probably an effect of a RoR bug: https://github.com/rails/rails/issues/8679
If I remove subdomain: 'api' inside the constraints block of the routes definition, all of Rails 3.2.21, 4.1.9 and 4-2-stable will accept the routes and work. If I force the spec to be a request spec and change the host! "api.#{host}" to host! "api.example.com", the routing also works.
Is this intentional? Is there an alternate way of restricting a route to a specific subdomain?
Related
I'm trying to write a controller test and Rspec isn't finding routes that I know exist and work fine on a development server.
In my routes I have a catch-all route that should redeirect to a generic controller if someone goes to a route that isn't predefined.
routes.rb
namespace :tools do
match '*unmatchedpath' => "generic#show", :via => :get
end
generic_controller.rb
def show
# do stuff
end
generic_controller_spec.rb
require 'spec_helper'
describe Tools::GenericController do
describe 'GET show' do
it 'does stuff' do
get :show
end
end
Here is the error I get from rspec when I run the test above
1) Tools::GenericController GET show does stuff
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"tools/generic", :action=>"show"}
All routes work as expected on my development server so I'm not sure why Rspec isn't finding the route.
Try:
get '*unmatchedpath' => 'tools/generic#show'
I have a rails 4 api application in which I capture all missing routes like this:
namespace :api, defaults: {format: :json} do
namespace :v1 do
# matchers ...
end
# catch all undefined paths and redirect them to the errors controller
match "*path", to: "errors#routing_error", via: :all
end
With a simple click through test, this seems to work like a charm, however I'd like to write
an rspec test for this behaviour.
In my Rspec spec I try the following:
it "should capture non existing action" do
get '/api/non-existing-action', format: :json #Note that non-existing-action is not defined in the routes.rb
#expectations come here
end
The problem is that Rspec seem to catch the routing error before the router and raises a default error like this one
ActionController::UrlGenerationError:
No route matches {:action=>"/api/non-existing-action", :controller=>"api/api", :format=>:json}
So my question is: Is there a way to tell Rspec that it should let my router handle the non existing path, so that I can expect the error response from my errors controller?
I am trying to port my application from Rails 3.2.x to Rails 4.0.4. All the gems have been made compatible and I am in the phase of fixing failing tests.
I have this weird test failure.
My routes.rb
resources :my_reports, only: [:index] do
collection do
get "/report/:filename", to: :show, prefix: "pri/excl/rep", as: :show
end
end
My spec which has been passing in Rails 3.2.x and now failing after update to 4.0.4
describe MyReportsController do
describe "#show" do
def make_request
get :show, prefix: 'some/place', filename: 'foo', format: 'doc'
end
it "makes a simple request" do
make_request
end
end
end
I am getting the following error
Failure/Error: get :show, prefix: 'some/place', filename: 'foo', format: 'doc'
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"my_reports",
:filename=>"foo", :format=>"doc", :prefix=>"some/place"}
I am stuck at this point, hints are welcome. I am using rspec and rspec-rails versions 2.14.1.
Passing a dummy :id in the test fixed the issue for me although I would not like it, tests pass.
get :show, id: "", prefix: 'some/place', filename: 'foo', format: 'doc'
Refer to state of rails releases here.
You're describing the show method but your route is only available for the index one. Maybe it's a beginning of solution.
Routes that work fine in my application fail on any get/put call in rspec testing with 'No route matches'. What am I doing wrong here?
Here's a simple example, from contracts_controller_spec.rb:
it 'should redirect to edit on show' do
get :show
response.should be_success
response.should render_template(:edit)
end
The above fails with the following:
ContractsController api calls should redirect to edit on show
Failure/Error: get :show
ActionController::RoutingError:
No route matches {:controller=>"contracts", :action=>"show"}
the show method in contracts_controller.rb:
def show
Rails.logger.debug("getting contract info....")
get_contract_info
Rails.logger.debug("...got contract info.")
render :action => :edit
end
routes.rb content:
resource :contract, :only=>[:show, :edit, :update], :protocol =>ROUTES_PROTOCOL do
member do
get :print
end
end
rake routes output:
print_contract GET /contract/print(.:format) contracts#print {:protocol=>"http"}
edit_contract GET /contract/edit(.:format) contracts#edit {:protocol=>"http"}
contract GET /contract(.:format) contracts#show {:protocol=>"http"}
PUT /contract(.:format) contracts#update {:protocol=>"http"}
using rspec-rails 2.14.0
This app was recently upgraded from Rails 2.3 to 3.2, which has otherwise been successful
note the non-standard show/edit routes: no id is required, and forcing an id still results in No route matches {:controller=>"contracts", :id=>"1", :action=>"show"}
:protocol is bit weird, try to remove ??
I'm building a Rails engine under Rails 3.0.12, but I'm having issues with routes when trying to write specs for my engine's controller.
The context
I've been following an Enginex layout. The engine is named Featuring and is not isolated. It does not declare routes by itself: there is no featuring/config/routes.rb file. Instead, a routes_for_feature method is provided for the main application to define engine-specific routes.
##
# featuring/lib/featuring/rails.rb
#
require 'featuring/rails/routing'
module Featuring
class Engine < ::Rails::Engine
end
end
##
# featuring/lib/featuring/rails/routing.rb
#
module ActionDispatch::Routing
class Mapper
def routes_for_feature(feature_name)
resource_name = feature_name.to_s.pluralize.to_sym
resources resource_name, :controller => "featuring/features", :only => [:index, :show], :feature => feature_name.to_s
end
end
end
Following the Enginex template, I have a Dummy app which define the routes as so:
# featuring/spec/dummy/config/routes.rb
Dummy::Application.routes.draw do
routes_for_feature :feature_model
end
The issue
Everything is working fine when I run the rails server for the Dummy app. I can browse to http://localhost:3000/feature_models and the request is successful.
I would like to spec my Featuring::FeaturesController, but I can't get it to find the routes.
Here is the spec:
# featuring/spec/controllers/features_controller_spec.rb
require 'spec_helper'
describe Featuring::FeaturesController do
context "feature_models" do
it "GET index should be successful" do
puts Rails.application.routes.routes
get :index, { :use_route => "featuring", :feature => "feature_models" }
response.should be_success
end
end
end
And here is the result of running this spec:
rspec spec/controllers/features_controller_spec.rb:7
Featuring::FeaturesController
feature_models
GET /feature_models(.:format) {:action=>"index", :controller=>"featuring/features"}
GET /feature_models/:id(.:format) {:action=>"show", :controller=>"featuring/features"}
GET index should be successful (FAILED - 1)
Failures:
1) Featuring::FeaturesController feature_models GET index should be successful
Failure/Error: get :index, { :use_route => "featuring", :feature => "feature_models" }
ActionController::RoutingError:
No route matches {:feature=>"feature_models", :controller=>"featuring/features"}
# ./spec/controllers/features_controller_spec.rb:8:in `block (3 levels) in <top (required)>'
As you can see, even if the routes are correctly defined, the spec'ed controller seems not to find them.
Something surprises me in the RoutingError: No route matches {:feature=>"feature_models", :controller=>"featuring/features"}. The action => "index" is not displayed.
I had a similar error, and I was also confused by the lack of {:action => "index"} in the route options. However, this turned out not to be the problem. ActionDispatch treats the lack of an :action as equivalent to {:action => "index"}. See:
https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/routing/route_set.rb#L545
You may be missing a request parameter in your spec, as was the case with me. Check the Parameters line in your server log when you load the page in the browser.
The trick is to add routes { } to your spec, like so:
describe Featuring::FeaturesController do
routes { Featuring::Engine.routes }
# ...
end
See also No Route Matches ... Rails Engine