[Rails 3] No route matches error using RSpec even though route DOES match

I’ve recently run into a really weird situation that I’m just not sure
what’s going on here. I’m trying to write a route that will allow
searches to be done via GET requests (generally a good idea since it’s
just retrieving information, helps for links and SEO, etc.), and I
have the route properly set up and can access it in development mode
just fine, but when running the controller spec, it triggers an
ActionController::RoutingError stating that there isn’t such a route
that exists.

The route in question:
match ‘/search/users/:name’, :to => ‘search#users’, :via => :get

The idea is that if a user goes to www.example.com/search/users/John+Doe
that the search controller passes the params: {:name => “John D.”} to
the “users” action. Indeed, if I run this through my browser, it
works perfectly fine.

The problem is when using RSpec, it doesn’t work at all. The
corresponding spec for this is:

require ‘spec_helper’

describe SearchController do
before :all do
Codebase::Application.reload_routes!
# a futile attempt to force new routes to be ready, still doesn’t
work
end

context “a GET to /users with a name” do
it “should spit out a list of users with that name” do
get :users, :name => URI.escape(User.make.name)
response.should be_success
end
end
end

Instead of getting a success (which I should given that the action
itself is essentially blank - it exists, just nothing inside it, no
before_filters or anything, and a view for it exists), I get:
ActionController::RoutingError: No route matches {:name => “Foo
%20Bar”, :controller => “search”, :action => “users”}.

Even more insidious, my output from rake routes:
GET /users/:name(.:format)
{:controller=>“search”, :action=>“users”}

This could be understandable if I could duplicate the problem for
other controller tests, but they all work fine! All my other
controllers are, so far, set up as REST-based resources, and they work
perfectly with standard things like get :index, or put :update, etc.
No routing errors there.

I don’t really see smushing this behavior into a resource set (with
URL-based parameters) as a good idea or a good way to solve this. I’d
like to know how I can get RSpec to play nice with my routes the way
they’re supposed to. Any ideas what’s going on here?

All right, I think I figured part of this out, but it’s
really …sloppy.

So apparently, Rails routes don’t like periods in their params. The
test data I had created was created using the Faker gem, and the
particular “name” attribute it created had a title of Mrs. in it, and
that period is what threw it off. If I hard-code it to something
like, “foo”, it passes.

So now the problem is, how do I tell the router to ignore periods, and
just pass them as part of the parameter, for that specific route?

Success! Cataloging here for future Googlers –

Section 3.2 of the Rails 3 guide to routing (http://
Rails Routing from the Outside In — Ruby on Rails Guides) says,

“By default dynamic segments dont accept dots this is because the
dot is used as a separator for formatted routes. If you need to use a
dot within a dynamic segment add a constraint which overrides this
for example :id => /[^/]/+ allows anything except a slash.”

Although, I think their regex pattern has s typo in it - given that I
suck with regexes, can somebody verify that it isn’t supposed to be /[^
/]+/ ? I’m getting some syntax oddities in my editor with the one in
the documentation (only difference: swap the + and final /
characters).

This causes my tests to pass, but I’m starting to wonder if I should
allow this contingency or not. Obviously Rails is using that dot for
some reason; what exactly do they mean by, “separator for formatted
routes” in the description above? I’m guessing /path/to/some/
resource.json or .xml or .html or whatever, but I could be wrong.
Could some one enlighten me here? Thanks! :slight_smile:

On 7 Apr 2011, at 12:29, Phoenix R. wrote:

Although, I think their regex pattern has s typo in it - given that I
suck with regexes, can somebody verify that it isn’t supposed to be /[^
/]+/ ? I’m getting some syntax oddities in my editor with the one in
the documentation (only difference: swap the + and final /
characters).

Yes, I think you’re right. That ‘+’ only makes sense inside the
regular expression, not outside it.

You can submit a fix here if you like; patches are readily accepted:

https://github.com/lifo/docrails

This causes my tests to pass, but I’m starting to wonder if I should
allow this contingency or not. Obviously Rails is using that dot for
some reason; what exactly do they mean by, “separator for formatted
routes” in the description above? I’m guessing /path/to/some/
resource.json or .xml or .html or whatever, but I could be wrong.
Could some one enlighten me here? Thanks! :slight_smile:

Yes, that’s correct. A ‘formatted route’ is one that has a ‘.json’ or
‘.xml’ or similar at the end. You can see it in use in the ‘rake routes’
output you quoted below:

GET /users/:name(.:format)
{:controller=>“search”, :action=>“users”}

If you decide that you want to use formats for that particular route in
future, then you’ll likely run into some problems. But otherwise, you
should be fine.

I guess one alternative would be to pass the ‘name’ parameter in the
querystring; then it has no chance of interfering with the route
recognition. Results in a less elegant URL, but then passing search
parameters in the querystring is a fairly common convention.

Chris