views:

108

answers:

2

I want to create a Rails 3 route with entirely optional parameters. The example broken route is:

match '(/name/:name)(/height/:height)(/weight/:weight)' => 'people#index'

Which results in 'rake:routes' yielding:

/(/name/:name)(/height/:height)(/weight/:weight)

And thus adding an initial slash to all links:

<a href="//name/kevin">...</a>

The route works if I specify it as:

match '/people(/name/:name)(/height/:height)(/weight/:weight)' => 'people#index'

But I want to have this as the root URL (as with the first example, which does not work). Thanks.

A: 

Does it work if you use a separate root mapping?

root :to => 'people#index'
match '(/name/:name)(/height/:height)(/weight/:weight)' => 'people#index'

It does seem like a pretty major oversight in the new routing system.

There could be a way to hack it through a rack middleware (maybe overriding Rack::URLMap), but that's a little out of my league.

zaius
No, it does not work. Running rake:routes returns "/(/name/:name)(/height/:height)(/weight/:weight)" and the initial slash causes links to be "<a href="//name/kevin">...</a>".
Kevin Sylvestre
+1  A: 

I don't know if this can be done with Rails' routing engine, but you can add a custom middleware to your stack and it should work just fine.

Put this in lib/custom_router.rb

class CustomRouter
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['REQUEST_PATH'].match(/^\/(name|height|weight)/)
      %w(REQUEST_PATH PATH_INFO REQUEST_URI).each{|var| env[var] = "/people#{env[var]}" }
    end
    @app.call(env)
  end
end

and add

 config.middleware.use "CustomRouter"

to your config/application.rb.

You can then set the route like

match '/people(/name/:name)(/height/:height)(/weight/:weight)' => 'people#index'

and it will work.

andi
Thanks Andi. This is what I needed! I greatly appreciate the help. Just awesome answer.
Kevin Sylvestre