Don’t go too overboard with this stuff – it’s meant primarily for internal (to Rails) usage…
The march to RESTful nirvana continues with a drop dead easy way to build nested resource URLs. Let’s review.
Assuming the following routing configuration:
1 2 3 |
map.resources :categories do |categories| categories.resources :articles end |
This automatically builds a category_url(category) and category_article_url(category, article) helper (among others) that will build the appropriate URLs:
1 2 |
category_url(@category) #=> /categories/1 category_article_url(@category, @article) #=> /categories/1/article/1 |
All right, that’s great. But why should we have to spell out these lengthy helper method calls when it’s clear that the first argument is a Category and the second is an Article? Can’t the appropriate helper method be implied by the types of these arguments? Yes – they can, and now they are with the new url_for update. Now you can pass in a collection of models to url_for, in order of nesting (root to child), and get the correct URL:
1 2 |
url_for(@category) #=> /categories/1 url_for([@category, @article]) #=> /categories/1/article/1 |
You can always fall back to the named routes provided for you by RESTful routing, but you now have an option to build URLs with an implied resource nesting.
tags: ruby, rubyonrails, REST

hi there, to my understanding this won’t work if we don’t have a resources but resource? ie.
map.resource :account do |account| account.resource :tags end
when using url_for(tag) in a cycle, for example, it will spell out an error, telling that tag_path is not valid (should be automatically account_tag_path). I assume this is an intended behavior?
bad formatting.. trying again.
Wow, i’m so not digging this at all. I’d rather the method name be expressive, than the parameters that are being passed in.
If anything i’d like the requirement of passing in every object to be removed. This could be Anyone that’s had to take a top level model and nest it into something after a project was completed knows the pains of having to go back to EVERY routing method to change this. Its painful.
article_path(@article) is much more beautiful and expressive than this url_for([@category, @article])
It should play quite nice with the parent object approach described here – http://revolutiononrails.blogspot.com/2007/05/drying-up-polymorphic-controllers.html … Building of a nested url will be a matter of calling url_for([@parent_object, @child_object]).
I’m with Jon. There’s a point where minimalism and laziness will start getting in the way of productivity and ability of others to understand your code easily. This is getting to that point way too close.
I for one think it is a better more understandable approach than the existing restful helpers.
`article_path(@article) => url_for([@category, @article])`
is not a fair comparison, since your beef was with removing the requirements for passing in parent objects. More fairly:
`article_path(@article) => url_for(@article)`
I’d much prefer the latter. especially when you get into: ` category_article_comment_path(@category, @article, @comment) url_for([@category, @article, @comment]) ` Which is more readable to you?
Now that I’m running edge I can start using this right away! I’m a little skeptical about the edge cases here, but I don’t exactly buy Jon’s argument. The correct comparison would be article_path(@article) to url_for(@article). I don’t see how the second one is any less expressive unless your instance variable name isn’t expressive.
Unless he’s talking about the whole nested resources thing, but that’s a separate issue.
My issues were separate.
Per the new method though,
article_path(@article) => url_for([@category, @article])
I like the old way better.
category_article_comment_path(@category, @article, @comment) => url_for([@category, @article, @comment])
I may be missing some info here because I haven’t yet moved to back to edge since 1.2 went final. Is this the new appropriate way to use named restful routes? If so, its quite hideous. If we should make any assumptions i belive it can be about the model. The developer SHOULD be familiar with it. So having a verbose method name like that for a path is a bit overkill.
If this is the case, then a shorter url_for would be nicer, but its still not as nice as comment_path(@category, @article, @comment). I think the method should expose where the resulting url will point to, not the last param in the signature.
My point about removing the extra parameters was that if effort was put into cleaning up the restful named routes, then it should have been put into geting rid of the requirement of the parent objects. And i know…... i was that ‘how to contribute to rails’ talk at railsconf ;)
Why url_for([@category, @article]) instead of url_for(@category, @article) ?
Putting them in an array seems unintuitive.
The real juicy bit is that from now on this also works in form_for, Simply Helpful Plus Plus style. The awesomes.
@Carl Porth: Agreed. However, perhaps when options are passed in, things get confusing?
Hendrik Mans: Hm, but this doesn’t replace the [@parent,@child] patch for Simply Helpful, or how did you mean that? SimplyHelpful would have problems distinguishing between new/edit afaik
Hendrik Mans: Hm, but this doesn’t replace the [@parent,@child] patch for Simply Helpful, or how did you mean that? SimplyHelpful would have problems distinguishing between new/edit afaik
Does this change play nicely with the new namespace feature that was added to routing in edge?
Also, I always wondered why you would have to write:
When you can derive @article and @category from @comment, eg:
category_article_comment_path(@comment)Right now there seems to be a bug with the new namespacing? but I guess bitsweat is fixing this.
having users/x/efforts/y url_for([user,effort]) uses the corret new user_efforts… path but form_for([user,effort]) tries to find efforts_url
Guys, guys. This addition to url_for is NOT meant to be used by end-users directly. It’s there to allow other helpers, like form_for, get to these nested resources.
You should never/vey rarely call url_for with an array like this by hand. We’ll make sure the documentation reflects this.
How would you use it with form_for then? Like the Simply Helpful patch does?