Using url_for With Nested Resources in Rails
April 6, 2010
I was recently making a field that would contain a url that when you clicked on the field, it would auto select the contents. This way people could click in the field and copy the url there easily. I achieved this successfully using Barry Hess’ helper method.
However, I wanted to put a url for the current page in that field, and getting that out of Rails proved difficult on the first attempt. After an initial attempt at getting rails to give me the current page’s url, I figured out two ways to get the link that weren’t particularly Railsy, until finally I found a Rails way of doing things.
The first wrong way was to hardcode the url, adding various variables to pick up the initial resource and it’s nested child object. This wasn’t a very good way of doing things because what if I moved domains? I would have to recode it.
The second wrong way was to get the url from the request object, using “request.url”. This was fairly concise, but not preferable. Explicitly accessing the request object seemed silly. There had to be a way were I could get one of those magic paths out of Rails.
The solution was to use a nested route like this, concept_example_path (meaning: resource_nestedResource_path). And then to make sure I was getting a complete url, I needed to suppress the default behavior of url_for with :only_path => false.
My initial code looked like this:
url_for(concept_example_path, :only_path => false)
but this returns a “wrong number of arguments (2 for 1)” error.
After poking around I found the proper way to get around the error is to write it like so:
url_for(concept_example_path(:only_path => false))
That gave me a full url (like: http://localhost:3000/concepts/1/examples/1) and not just the path info (/concepts/1/examples/1) for the concept and example objects. You’ll now have an intelligent url for your resources that will change dynamically if you switch domains.
Also, you may find the urlHelper part of the Ruby on Rails API useful, if you haven’t already looked there.