diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index f2e7c2351e6ae..3a18e2a121f16 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -35,7 +35,8 @@ def to_param class Hash # Converts a hash into a string suitable for use as a URL query string. An optional namespace can be - # passed to enclose the param names (see example below). + # passed to enclose the param names (see example below). The keys in the query string are sorted lexicographically + # in ascending order. # # ==== Examples # { :name => 'David', :nationality => 'Danish' }.to_param # => "name=David&nationality=Danish" @@ -44,6 +45,6 @@ class Hash def to_param(namespace = nil) collect do |key, value| value.to_query(namespace ? "#{namespace}[#{key}]" : key) - end * '&' + end.sort * '&' end end diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index e5438745e00b8..0f35eb9e78d06 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -462,20 +462,24 @@ def test_string_hash assert_equal '', {}.to_param assert_equal 'hello=world', { :hello => "world" }.to_param assert_equal 'hello=10', { "hello" => 10 }.to_param - assert_equal 'hello=world&say_bye=true', ActiveSupport::OrderedHash[:hello, "world", "say_bye", true].to_param + assert_equal 'hello=world&say_bye=true', {:hello => "world", "say_bye" => true}.to_param end def test_number_hash - assert_equal '10=20&30=40&50=60', ActiveSupport::OrderedHash[10, 20, 30, 40, 50, 60].to_param + assert_equal '10=20&30=40&50=60', {10 => 20, 30 => 40, 50 => 60}.to_param end def test_to_param_hash - assert_equal 'custom=param-1&custom2=param2-1', ActiveSupport::OrderedHash[ToParam.new('custom'), ToParam.new('param'), ToParam.new('custom2'), ToParam.new('param2')].to_param + assert_equal 'custom2=param2-1&custom=param-1', {ToParam.new('custom') => ToParam.new('param'), ToParam.new('custom2') => ToParam.new('param2')}.to_param end def test_to_param_hash_escapes_its_keys_and_values assert_equal 'param+1=A+string+with+%2F+characters+%26+that+should+be+%3F+escaped', { 'param 1' => 'A string with / characters & that should be ? escaped' }.to_param end + + def test_to_param_orders_by_key_in_ascending_order + assert_equal 'a=2&b=1&c=0', ActiveSupport::OrderedHash[*%w(b 1 c 0 a 2)].to_param + end end class HashToXmlTest < Test::Unit::TestCase