diff --git a/lib/grape/endpoint.rb b/lib/grape/endpoint.rb index 2db50cc1b..9b1cf635b 100644 --- a/lib/grape/endpoint.rb +++ b/lib/grape/endpoint.rb @@ -1,5 +1,6 @@ require 'rack' require 'grape' +require File.dirname(__FILE__) + '/helpers/extensions/hash' module Grape # An Endpoint is the proxy scope in which all routing @@ -30,7 +31,11 @@ def self.call(env) def params @params ||= request.params.merge(env['rack.routing_args'] || {}).inject({}) do |h,(k,v)| h[k.to_s] = v - h[k.to_sym] = v + + # Also return a version of the parameters with symbols as hash keys + v_sym = (v.kind_of?(Hash) && v.respond_to?(:key_strings_to_symbols)) ? v.key_strings_to_symbols : v + h[k.to_sym] = v_sym + h end end diff --git a/lib/grape/helpers/extensions/hash.rb b/lib/grape/helpers/extensions/hash.rb new file mode 100644 index 000000000..3646601d1 --- /dev/null +++ b/lib/grape/helpers/extensions/hash.rb @@ -0,0 +1,12 @@ +class Hash + # Recursively replace key names that should be symbols with symbols. + def key_strings_to_symbols + new_hash = Hash.new + self.each_pair do |k,v| + new_value = (v.kind_of?(Hash) && v.respond_to?(:key_strings_to_symbols)) ? v.key_strings_to_symbols : v + new_key = k.kind_of?(String) ? k.to_sym : k + new_hash[new_key] = new_value + end + new_hash + end +end \ No newline at end of file diff --git a/spec/grape/endpoint_spec.rb b/spec/grape/endpoint_spec.rb index 3a90b0ca4..de5429b26 100644 --- a/spec/grape/endpoint_spec.rb +++ b/spec/grape/endpoint_spec.rb @@ -48,6 +48,42 @@ def app; subject end get '/hey/12' last_response.body.should == '12' end + + it 'returns a hashed version of parameters which are hashes with symbol keys' do + subject.get('/hey') do + "#{params[:location][:city]}, #{params[:location][:state]}" + end + + get '/hey?location[city]=New%20York&location[state]=NY' + last_response.body.should == "New York, NY" + end + + it 'returns a hashed version of parameters which are hashes with string keys' do + subject.get('/hey') do + "#{params['location']['city']}, #{params['location']['state']}" + end + + get '/hey?location[city]=New%20York&location[state]=NY' + last_response.body.should == "New York, NY" + end + + it 'returns a hashed version of parameters which are hashes with symbol keys multiple levels deep' do + subject.get('/hey') do + params[:location][:city][:neighborhood] + end + + get '/hey?location[city][neighborhood]=Chelsea' + last_response.body.should == "Chelsea" + end + + it 'returns a hashed version of parameters which are hashes with string keys multiple levels deep' do + subject.get('/hey') do + params['location']['city']['neighborhood'] + end + + get '/hey?location[city][neighborhood]=Chelsea' + last_response.body.should == "Chelsea" + end end describe '#error!' do