收录日期:2020/09/28 22:55:46 时间:2013-08-21 14:43:47 标签:ruby-on-rails,routing,ruby-on-rails-3,rspec,constraints

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?

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.

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

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