RestClient为什么会将哈希数组参数中的所有哈希值都剥离,只留下最后一个?

11

我有一个需要将参数作为哈希数组传递的条件,它长得像这样:

以下是用于API调用的Rack::Test post方法。

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 post方法来调用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 要将哈希数组剥离成只有最后一个哈希呢?

你确定 @param_data 是你想要的吗?我正在使用 RestClient,没有出现过这样的问题。 - d11wtq
这是 @param_data 的值:[{:Company => "Google", :Website => "google.com"}, {:Company => "Times", :Website => "times.com"}] - millisami
2个回答

19

我在我们的Rails应用程序中遇到了同样的问题。我发现以下解决方法可以与RestClient + Rails后端一起使用:

Rails期望数据[ ][Company]。请使用"data[]"而不是"data"作为键。例如:

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

1
这对我没有用。我们发现本地的JSON格式不能按预期处理数组,因此不得不使用接受答案中提到的{"1"=>{...data...},{"2"=>{...data2}}方法,这是JSON中的本地“数组”。 - James
1
第二个解决方案(深度嵌套)对我们起作用了。我想知道你是如何设法搞清楚这个疯狂的问题的?不管怎样,谢谢你。 - so_mv

14

我猜测这与它们将哈希转换为参数的方式有关。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[][Company]=Apple,Inc&data[][Website]=Apple.com&data[][Company]=Google&data[][Website]=google.com

Rails URI解析器需要读取这段内容并将其转换回哈希表。在我看来,将散列数组放入参数中会导致麻烦,因为它创建了一个字符串(如上所示),基本上难以解析。例如,当面对这两个参数时:

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

解析器可能会认为它们都在描述名为"data"的数组中的第一个哈希中的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可能是某个公司记录的实际ID,也可能只是您输入的一些数字,用于生成唯一键,而这些唯一键在另一端被丢弃。这将生成以下参数:

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

1
这可能与RestClient本身有关。因为当我使用HTTParty进行POST请求时,它按预期工作,而且我的代码没有任何调整。 `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)` - millisami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接