RestClient 只用最后一个哈希值去除哈希参数数组?

发布于 2024-11-16 08:55:13 字数 1477 浏览 11 评论 0原文

我有一个情况,我需要将参数作为哈希数组传递,如下所示:

以下是 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 将哈希数组剥离到最后一个数组的哈希值?

I have a condition where i need to pass a parameter as an array of hashes which looks like this:

The following is the Rack::Test post method for API call.

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

And this is the log of the rails app.

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

Now, this is the RestClient post method I'm using to call the API.

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

And this is the log of the rails app.

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

The difference is in the data parameter.

When sending with Rack::Test method, the data is passed as "data"=>[{"Company"=>"Apple,Inc", "Website"=>"Apple.com"}, {"Company"=>"Google", "Website"=>"google.com"}]

but via RestClient way, the parameter data array is stripped out and only the last hash is passed as "data"=>{"Company"=>"Google", "Website"=>"google.com"}

Why the RestClient is stripping out the array of hashes to just a last hash of the array?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尐籹人 2024-11-23 08:55:13

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

Rails 正在等待数据[][公司]。使用“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"}
      ]
    }
  }
}

I ran into the same problem with our rails application. I found the following workarounds to work with RestClient + Rails backend.

Rails is expecting data[][Company]. Use 'data[]' instead of 'data' as the key. For example:

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

In our case, we had an array nested two levels deep in the hash. The above workaround doesn't fix the problem because of the way RestClient formats the parameters. So, if you have an array that's nested deeper than the top level of the hash passed to RestClient, you have to use the following workaround:

RestClient.post 'http://archive.greenviewdata.com/containers', {
  :run => {:title => 'something'}, 
  :nested => {
    'data' => {
      '' => [
        {"Company"=>"Apple,Inc","Website"=>"Apple.com"},
        {"Company"=>"Google","Website"=>"google.com"}
      ]
    }
  }
}
一个人的夜不怕黑 2024-11-23 08:55:13

我怀疑这与它们将哈希转换为参数的方式不同有关。 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

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

I suspect it's to do with differences in how they convert a hash into params. Rack::Test will probably be using Hash#to_param, which gives the following results:

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

This is the troublesome part:

data[][Company]=Apple,Inc&data[][Website]=Apple.com&data[][Company]=Google&data[][Website]=google.com

The rails uri parser has to read this and turn it back into a hash. In my opinion putting an array of hashes into your params is asking for trouble as it creates a string, like the above, which is fundamentally difficult to parse. For example, presented with these two params

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

The parser may decide that both of them are describing the Company variable in the first hash in the array called "data", and so overwrite the first with the second, which is what's happening with you.

It sounds like your problem is at the generation stage rather than the intepretation stage, but still, i would try to create a cleaner scheme for your parameters, in which arrays are only ever used as the final part of the param name, (ie use a hash instead of an array to hold company data) and you instead insert some unique keys to differentiate the company hashes from each other. Something like this:

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

1 and 2 could be the actual ids of some company record, or they could just be some numbers you put in to make unique keys, which are chucked away at the other end. This will generate params like this:

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

Which are now in no danger of overwriting each other.

In your subsequent controller action, it's just a change from doing this:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文