From d9b6f08ce5f847ae7ebda691b2c1d5d4dd18f92b Mon Sep 17 00:00:00 2001 From: Brandur Date: Thu, 25 Aug 2016 10:54:08 -0700 Subject: [PATCH] Don't alphabetize encoded maps by key Alphabetizing maps being encoded by key can cause problems because the server side Rack relies on the fact that that a new array item will start with a repeated key. For example, given this encoding: ``` items: [ { :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk' }, { :type => 'discount', :amount => -10000, :currency => 'cad', :description => 'potato' } ], ``` We need to have `type` appear first so that an array boundary is recognized. So the encoded form should take: ``` items[][type]=sku&items[][parent]=...&items[][type]=discount&items[][amount]=... ``` But currently `type` gets sorted to the back, so we get something more like: ``` items[][parent]=...&items[][type]=...&items[][amount]=...&items[][currency]=...&items[][description]=...&items[][type]=potato ``` Which the server will receive as this: ``` items: [ { :type => 'sku', :parent => 'sku_94ZYSC0wppRTbk', :amount => -10000, :currency => 'cad', :description => 'potato' } { :type => 'discount' } ], ``` Here we remove the alphabetization to fix the problem and correct a bad test. --- lib/stripe/util.rb | 2 +- test/stripe/account_test.rb | 2 +- test/stripe/util_test.rb | 12 ++++++------ 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/stripe/util.rb b/lib/stripe/util.rb index 60e46b8f..89e5ab16 100644 --- a/lib/stripe/util.rb +++ b/lib/stripe/util.rb @@ -135,7 +135,7 @@ module Stripe # do not sort the final output because arrays (and arrays of hashes # especially) can be order sensitive, but do sort incoming parameters - params.sort_by { |(k, _)| k.to_s }.each do |key, value| + params.each do |key, value| calculated_key = parent_key ? "#{parent_key}[#{key}]" : "#{key}" if value.is_a?(Hash) result += flatten_params(value, calculated_key) diff --git a/test/stripe/account_test.rb b/test/stripe/account_test.rb index 1f6dc3f7..0b12331f 100644 --- a/test/stripe/account_test.rb +++ b/test/stripe/account_test.rb @@ -105,7 +105,7 @@ module Stripe } @mock.expects(:post). once. - with('https://api.stripe.com/v1/accounts/acct_foo', nil, 'legal_entity[address][line1]=2+Three+Four&legal_entity[first_name]=Bob'). + with('https://api.stripe.com/v1/accounts/acct_foo', nil, 'legal_entity[first_name]=Bob&legal_entity[address][line1]=2+Three+Four'). returns(make_response(resp)) a = Stripe::Account.update('acct_foo', :legal_entity => { diff --git a/test/stripe/util_test.rb b/test/stripe/util_test.rb index c7aa40dc..013431e9 100644 --- a/test/stripe/util_test.rb +++ b/test/stripe/util_test.rb @@ -36,8 +36,8 @@ module Stripe [:d, { :a => "a", :b => "b" }], [:e, [0, 1]], [:f, [ - { :bar => "1", :foo => "2" }, - { :baz => "3", :foo => "4" }, + { :foo => "1", :ghi => "2" }, + { :foo => "3", :bar => "4" }, ]], ] assert_equal([ @@ -52,10 +52,10 @@ module Stripe # *The key here is the order*. In order to be properly interpreted as # an array of hashes on the server, everything from a single hash must # come in at once. A duplicate key in an array triggers a new element. - ["f[][bar]", "1"], - ["f[][foo]", "2"], - ["f[][baz]", "3"], - ["f[][foo]", "4"], + ["f[][foo]", "1"], + ["f[][ghi]", "2"], + ["f[][foo]", "3"], + ["f[][bar]", "4"], ], Stripe::Util.flatten_params(params)) end