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"}

Теперь это метод публикации RestClient, который я использую для вызова 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 удаляет массив хэшей только до последнего хэша массива?


person Autodidact    schedule 22.06.2011    source источник
comment
Вы уверены, что @param_data это то, что вы думаете? Я использую RestClient и не видел таких проблем.   -  person d11wtq    schedule 22.06.2011
comment
Это значение @param_data = [{:Company => "Google", :Website => "google.com"}, {:Company => "Times", :Website => "times.com"}]   -  person Autodidact    schedule 23.06.2011


Ответы (2)


Я подозреваю, что это связано с различиями в том, как они преобразуют хэш в параметры. 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" 

Это проблемная часть:

data[][Компания]=Apple,Inc&data[][Веб-сайт]=Apple.com&data[][Компания]=Google&data[][Веб-сайт]=google.com

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

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

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

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

{: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
person Max Williams    schedule 27.06.2011
comment
Это может иметь какое-то отношение к самому RestClient. Потому что, когда я делаю почтовый запрос с помощью HTTParty, он работает, как и ожидалось, без каких-либо изменений в моем коде. options = { :body => { :api_key => Api_key, :data =>{:run => { :title => "runsdsd" }, :inputs => [{"Company"=>"Apple,Inc"},{"Company"=>"Google"}] } } } run = HTTParty.post("#{Url}/api/v1/lines/kapil/line2/runs.json",options) - person Autodidact; 14.07.2011

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

Rails ожидает данные[][Company]. Используйте «данные []» вместо «данные» в качестве ключа. Например:

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"}
      ]
    }
  }
}
person Philippe Green    schedule 05.12.2011
comment
это не сработало для меня. мы обнаружили, что этот собственный формат json не обрабатывает массивы, как ожидалось, и были вынуждены использовать метод {1=›{...data...},{2=›{...data2}}, упомянутый в принятом ответ, который является собственным массивом в json - person James; 10.09.2013
comment
Второе решение (глубоко вложенное) сработало для нас. Мне интересно, как вам удалось разобраться в этом сумасшествии? В любом случае, спасибо. - person so_mv; 28.09.2013