Nested Hash Params with Named Routes in Ruby on Rails 3
I've never (as of rev 5522) been able to pass a nested hash as parameters to url_for and have it flatten it properly on the generated URL. I encountered the problem again the other day and, having had just about enough, decided to try and nip it in the bud.
The problem I was having occurred when tried to make an HTTP request to a named route such as:
people_url(:person => { :name => 'Bob', :profession => 'Developer' }) When I've encountered this problem in the past, I could never find any information from someone who's actually solved the problem. There are a few patches submitted as tickets to the Rails devs, but one seems to be a duplicate of the other, and neither seems to fix this problem on Edge, at least not for my particular use case.
The root of this particular problem lies in a method in the action_controller/routing.rb file within actionpack/actioncontroller, in the options_as_params of the RoutingSet class. The method, without comments, looks like this:
1 2 3 4 5 6 7 | |
value is a Hash. In that case, the to_param method simply converts the Hash instance into its String representation, which is just a pile of keys and values mashed together, as in my people_url example.
To solve this problem, I changed the method to look like this:
def options_as_params(options)
options_as_params = options[:controller] ? { :action => "index" } : {}
options.parameterize do |param_key, param_value|
options_as_params[param_key] = param_value.to_param
end
options_as_params
end parameterize method is an extension I made to the Hash class that essentially flattens a hash like:
{
:person => {
:name => 'Bob',
:profession => 'Developer'
}
} {
:'person[name]' => 'Bob',
:'person[profession]' => 'Developer'
} class Hash
def flatten(superkey)
flattened_hash = {}
self.each do |key, value|
flattened_hash["#{superkey}[#{key}]".to_sym] = value
end
flattened_hash
end
def parameterize
self.each do |k, value|
if value.is_a?(Hash)
value.flatten(k).each { |fk, fv| yield fk, fv }
else
yield k, value
end
end
end
end 