generated urls within namespaced controllers

Hello,

I've run across an issue with namespaced controllers and url generation.

From http://github.com/rails/rails/tree/master/actionpack/lib/action_controller/routing/route_set.rb (line 322) I'm wondering what the purpose of the section of code with this comment is:

# if the controller has changed, make sure it changes relative to the # current controller module, if any. In other words, if we're currently # on admin/get, and the new controller is 'set', the new controller # should really be admin/set.

My scenario is the following...

I have view layout code with link_to's the use a hash to specify the url

link_to 'Example', {:controller => 'nonamespace', :action => 'index'}

which generates "/nonamespace"

But when I access a controller that is namespaced such as "/namespace/blah/action", that same link_to now generates "/namespace/nonamespace"

So from what I can tell the routing code is making an assumption that I don't think it should which seems to be that generated urls (sepcified with a hash) should remain in the context of the current views controller. In my case it's code for a layout which can apply to many controllers, so this assumption is incorrect and causing this issue.

Can somebody explain the assumption made by the routing code and if this is indeed a bug?

Thanks, Andrew

Whether it's a bug or not is kind of a matter of interpretation. But the *original intention* here was to support nested controllers with relative links. So, f.ex:

Admin - UsersController - TagsController UsersController

If you're in admin/tags/somethign and link to :controller=>'users'. Where is it meant to go? With the current behaviour it will go to /admin/users which is 'probably' a reasonable assumption.

You can work around this with :controller=> '/nonamespace' which will work from anywhere.

I'm interested in people's opinions on this one, we can't really change it for 2.2, but for the 2.3.x series we could try and rationalise all this stuff.

+1 to the current behaviour... it's just like accessing a relative file path vs an absolute one.

Cheers.

Except that using "/" for absolute vs nothing for relative has never been a recommended approach when working with parameterized (hash) urls. There is A LOT of code (almost certainly a valid assumption) that does not use the "/" method of specifying the controller (which is what I have used at the moment) and this nesting behaviour will certainly break that code as soon as a nested controller is used.

For me a nested controller is the exception to the norm, not the other way around.

-1 to the current behavior.

Except that using "/" for absolute vs nothing for relative has never been a recommended approach when working with parameterized (hash) urls. There is A LOT of code (almost certainly a valid assumption) that does not use the "/" method of specifying the controller (which is what I have used at the moment) and this nesting behaviour will certainly break that code as soon as a nested controller is used.

It's actually been the recommended approach since before 1.0 shipped. This behaviour has been around for a long long time, and we'd need an alternative way to distinguish between the nested and non-nested controller if we were to change it.

For me a nested controller is the exception to the norm, not the other way around.

-1 to the current behavior.

What solution do you have in mind?

I've been using Rails almost since it's inception and have never seen reference to using "/blah" as the recommended approach. If it was the recommended approach, I'd expect the docs and books to use the "absolute" style as well, but they don't use it.

I just took a look at the url_for and link_to docs. There is nothing to suggest using "/" in link_to, but the closest I found was in the url_for docs was "If the controller name begins with a slash, no defaults are used: url_for :controller => '/home'"

So ok, it may have been a recommended approach, but there's almost no reference to it. I didn't figure out to use "/" myself until I looked at the code.

Regarding a solution I have in mind, I'm not really sure. Since nested controllers are a lot less common in practice, my thoughts are towards fixing that end of the stick. Would passing :nested => true be a somewhat acceptable approach? That's just a quick thought that springs to mind.

Andrew

I've been using Rails almost since it's inception and have never seen reference to using "/blah" as the recommended approach. If it was the recommended approach, I'd expect the docs and books to use the "absolute" style as well, but they don't use it.

I think that the non-existent documentation for routes won't provide a valid precedent for any argument. Essentially nothing was documented, so looking for justification for anything in there is a sure road to frustration.

Regarding a solution I have in mind, I'm not really sure. Since nested controllers are a lot less common in practice, my thoughts are towards fixing that end of the stick. Would passing :nested => true be a somewhat acceptable approach? That's just a quick thought that springs to mind.

I realise the result can be surprising if this is the first time you've used modules, but we can't go breaking every application that uses this functionality without good cause. This really is just a question of relative or absolute paths, and everything I can think of defaults to relative.

File.open("tmp") doesn't default to /tmp. <a href="index.html"> doesn't default to /index.html.

I don't see why routes should be any different.

However in your case, the route points to some nonsense controller that doesn't even exist. We could change *that* behaviour without breaking anything.

However in your case, the route points to some nonsense controller that doesn't even exist. We could change *that* behaviour without breaking anything.

That was my other thought actually as well; check the controller "name" to see if it actually exists.

To me this seems like a pretty good compromise. I doubt anyone's expecting url_for to point to non-existent controllers, and if they are, it's hardly unreasonable for this to be fixed.

This will involve a trip into the bowels of the routes implementation, but hopefully you come up better for the experience :slight_smile:

however...

<a href="missing.html"> is still non-existant... it doesn't take a look around for /missing.html as well

...and, this would also mean that an admin/users controller which referenced a url_for :controller => 'pages' would access /pages up until the moment you add admin/pages and then the behaviour would change.

too much magic for my liking.

document the existing behaviour properly and it is consistent (and well documented).

cheers.

Heh, you've got two for the price of one, url_for and guide :-):

http://github.com/lifo/docrails/commit/1915d7ccce99a35c1a5e95e639760168a4bcc99f http://github.com/lifo/docrails/commit/8a2820ada320a3bc7fcf8c6f3513d10039d650ad

I think the first time I saw this was in the source code of acts_as_authenticated.