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

现在,这是我用来调用 API 的 RestClient post 方法。

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 将散列数组剥离为数组的最后一个散列?

4

2 回答 2

19

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

Rails 期待 data[][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"}
      ]
    }
  }
}
于 2011-12-05T20:10:35.843 回答
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[][公司]=Apple,Inc&data[][网站]=Apple.com&data[][公司]=Google&data[][网站]=google.com

rails 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 可能是某些公司记录的实际 ID,或者它们可能只是您输入的一些数字,用于制作唯一密钥,这些数字在另一端被丢弃。这将生成如下参数:

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

现在它们没有相互覆盖的危险。

在您随后的控制器操作中,这只是这样做的一个变化:

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

params[:data].each do |k, company_hash|
  #do something with company hash and optionally k if you want, or ignore k
end
于 2011-06-27T09:08:19.823 回答