5

Given a couple of cities in the DB:

City.first.attributes => {:id => 1, :name => 'nyc'}
City.last.attributes =>  {:id => 2, :name => 'boston'}

And a route like:

match '/:city/*dest' => 'cities#do_something', :constraints => {:city => /#{City.all.map{|c| c.name}.join('|'}/}

(so the constraints should evaluate to: /nyc|boston/)

And a spec:

it "recognizes and generates a route for city specific paths" do
  { :put => '/bad-city/some/path' }.should route_to({:controller => "cities", :action => "do_something", :dest => 'some/path', :city => 'bad-city'})
end

I would expect a failure. But it passes.

Likewise:

it "doesn't route bad city names" do
  { :put => '/some-bad-city/some/path' }.should_not be_routable
end

Here I expect it to pass, but it fails.

It seems the constraint is being ignored in the specs, since the matching cities have the same behavior as the bad ones.

Is this a known issue, or am I missing something that I need to do?

1
  • Because this works in dev, but not test, I'm thinking the problem is that the constraint is evaluated at startup, and in the test DB there are no cities at that point. So the regex looks like //, and matches everything. But when I try to make it a Proc, or a class implementing #matches?(request) it never seems to get called. Commented Oct 4, 2010 at 18:16

2 Answers 2

11

This approach works: In routes.rb

match '/:city/*destination' => 'cities#myaction', :constraints => {:city => /#{City.all.map{|c|c.slug}.join('|')}/}

In the spec:

describe "routing" do
  before(:each) do
    @mock_city = mock_model(City, :id => 42, :slug => 'some-city')
    City.stub!(:find_by_slug => @mock_city, :all => [@mock_city])
    MyApp::Application.reload_routes!
  end

  it "recognizes and generates a route for city specific paths" do
    { :get => '/some-city/some/path' }.should route_to({:controller => "cities", :action => "myaction", :destination => 'some/path', :city => 'some-city'})
  end

  it "rejects city paths for cities that don't exist in the DB" do
    { :get => '/some-bad-city/some/path' }.should_not be_routable
  end
end

Lastly, I added an observer to reload routes whenever the cities table changes.

Sign up to request clarification or add additional context in comments.

1 Comment

It's horrible to use a db find all in the routes.rb like that. In this case, the controller or a before_filter should validate the city.
0

When you specify constraints, you must include the parameter to constrain:

match '/:city/*dest' => 'cities#do_something', :constraints => { :city => /nyc|boston|philly/ }

1 Comment

You know - in my trying to simplify the problem, I introduced a typo. Thanks for the catch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.