RestClient выделяет массив параметров хэшей только с последним хешем?

У меня есть условие, когда мне нужно передать параметр как массив хэшей, который выглядит так:

Ниже приведен метод почты Rack:: Test для вызова API.

post "#{url}.json",
:api_key => application.key,
:data => [{"Company"=>"Apple,Inc","Website"=>"Apple.com"},{"Company"=>"Google","Website"=>"google.com"}],
:run => { :title => "The First Run" }

И это журнал приложения rails.

Parameters: {"api_key"=>"6a9acb84d0ea625be75e70a1e04d26360606ca5b", "data"=>[{"Company"=>"Apple,Inc", "Website"=>"Apple.com"}, {"Company"=>"Google", "Website"=>"google.com"}], "run"=>{"title"=>"The First Run"}, "line_id"=>"4e018e2c55112729bd00000a"}

Теперь это метод PostClient, который я использую для вызова API.

RestClient.post("/lines/#{@line.id}/runs.json", {:run => {:title => @title}, @param_for_input => @param_data})

И это журнал приложения rails.

Parameters: {"run"=>{"title"=>"run name"}, "data"=>{"Company"=>"Google", "Website"=>"google.com"}, "api_key"=>"f488a62d0307e79ec4f1e6131fa220be47e83d44", "line_id"=>"4e018a505511271f82000144"}

Разница заключается в параметре data.

При отправке с помощью метода Rack:: Test данные передаются как "data"=>[{"Company"=>"Apple,Inc", "Website"=>"Apple.com"}, {"Company"=>"Google", "Website"=>"google.com"}]

но с помощью метода RestClient массив данных параметров удаляется, и только последний хеш передается как "data"=>{"Company"=>"Google", "Website"=>"google.com"}

Почему RestClient лишает массив хэшей только последний хэш массива?

Ответ 1

Я подозреваю, что это связано с различиями в том, как они конвертируют хэш в параметры. Rack:: Test, вероятно, будет использовать Hash # to_param, который дает следующие результаты:

> params = {:api_key => "12345", :data => [{"Company"=>"Apple,Inc","Website"=>"Apple.com"},{"Company"=>"Google","Website"=>"google.com"}], :run => { :title => "The First Run" }}

> paramstring = params.to_param
 => "api_key=12345&data%5B%5D%5BCompany%5D=Apple%2CInc&data%5B%5D%5BWebsite%5D=Apple.com&data%5B%5D%5BCompany%5D=Google&data%5B%5D%5BWebsite%5D=google.com&run%5Btitle%5D=The+First+Run" 

> URI.unescape(paramstring)
 => "api_key=12345&data[][Company]=Apple,Inc&data[][Website]=Apple.com&data[][Company]=Google&data[][Website]=google.com&run[title]=The+First+Run" 

Это сложная часть:

данные [] [Компания] = Яблоко, Inc & данные [] [Сайт] = Apple.com & данные [] [Компания] = Google & данные [] [Сайт] = google.com

Анализатор uri rails должен прочитать это и включить его в хэш. На мой взгляд, набор массивов хэшей в ваши параметры задает проблемы, поскольку он создает строку, как и выше, что в корне трудно анализировать. Например, представленные этими двумя параметрами

data[][Company]=Apple,Inc
data[][Company]=Google

Парсер может решить, что оба из них описывают переменную Company в первом хэше в массиве, называемом "data", и поэтому сначала перезаписывают вторую, что и происходит с вами.

Похоже, ваша проблема на стадии покоя, а не на этапе интпретации, но все же я попытаюсь создать более чистую схему для ваших параметров, в которой массивы используются только как конечная часть имени параметра, (т.е. использовать хеш вместо массива для хранения данных компании), и вместо этого вы вставляете некоторые уникальные ключи, чтобы отличать хэши компании друг от друга. Что-то вроде этого:

{:api_key => "12345", 
 :data => {1 => {"Company"=>"Apple,Inc","Website"=>"Apple.com"}, 2 => {"Company"=>"Google","Website"=>"google.com"}}, 
 :run => { :title => "The First Run" }}

1 и 2 могут быть фактическими идентификаторами какой-либо записи компании, или просто могут быть некоторые номера, которые вы вводите, чтобы создавать уникальные ключи, которые отбрасываются на другом конце. Это создаст такие параметры:

data[1][Company]=Apple,Inc
data[2][Company]=Google

Теперь нет опасности переписывать друг друга.

В вашем последующем действии контроллера это просто изменение от этого:

params[:data].each do |company_hash|
  #do something with company hash
end

to

params[:data].each do |k, company_hash|
  #do something with company hash and optionally k if you want, or ignore k
end

Ответ 2

Я столкнулся с той же проблемой с нашим рельсовым приложением. Я нашел следующие обходные пути для работы с BackClient + Rails.

Rails ожидает данные [] [Компания]. Вместо "данных" в качестве ключа используйте "данные" [] ". Например:

RestClient.post 'http://archive.greenviewdata.com/containers', { 
  :run => {:title => 'something'}, 
  'data[]' => [
    {"Company"=>"Apple,Inc","Website"=>"Apple.com"},
    {"Company"=>"Google","Website"=>"google.com"}
  ]
}

В нашем случае у нас был массив, вложенный в два уровня в глубину хэша. Вышеописанное решение не устраняет проблему из-за того, как RestClient форматирует параметры. Итак, если у вас есть массив, который вложен глубже верхнего уровня хэша, переданного RestClient, вы должны использовать следующее обходное решение:

RestClient.post 'http://archive.greenviewdata.com/containers', {
  :run => {:title => 'something'}, 
  :nested => {
    'data' => {
      '' => [
        {"Company"=>"Apple,Inc","Website"=>"Apple.com"},
        {"Company"=>"Google","Website"=>"google.com"}
      ]
    }
  }
}