Rails没有正确解码jQuery中的JSON(数组成为带整数键的哈希)

ale*_*nde 89 arrays jquery post json ruby-on-rails

每次我想用jQuery向Jails发布一个JSON对象数组时,我就遇到了这个问题.如果我对数组进行字符串化,我可以看到jQuery正在正常工作:

"shared_items"=>"[{\"entity_id\":\"253\",\"position\":1},{\"entity_id\":\"823\",\"position\":2}]"
Run Code Online (Sandbox Code Playgroud)

但是如果我只是将它作为AJAX调用的数据发送给我:

"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}
Run Code Online (Sandbox Code Playgroud)

然而,如果我只发送一个普通数组,它的工作原理:

"shared_items"=>["entity_253"]
Run Code Online (Sandbox Code Playgroud)

为什么Rails将数组更改为那个奇怪的哈希?想到的唯一原因是Rails无法正确理解内容,因为这里没有类型(有没有办法在jQuery调用中设置它?):

Processing by SharedListsController#create as 
Run Code Online (Sandbox Code Playgroud)

谢谢!

更新: 我将数据作为数组发送,而不是字符串,并使用该.push()函数动态创建数组.尝试$.post$.ajax,相同的结果.

swa*_*jak 165

如果有人偶然发现并想要一个更好的解决方案,你可以在.ajax调用中指定"contentType:'application/json'"选项,并让Rails正确解析JSON对象,而不是将其整合到整数键哈希中,而不是 - 字符串值.

总而言之,我的问题是:

$.ajax({
  type : "POST",
  url :  'http://localhost:3001/plugin/bulk_import/',
  dataType: 'json',
  data : {"shared_items": [{"entity_id":"253","position":1}, {"entity_id":"823","position":2}]}
});
Run Code Online (Sandbox Code Playgroud)

导致Rails将事物解析为:

Parameters: {"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}}
Run Code Online (Sandbox Code Playgroud)

而这(注意:我们现在正在对javascript对象进行字符串化并指定内容类型,因此rails将知道如何解析我们的字符串):

$.ajax({
  type : "POST",
  url :  'http://localhost:3001/plugin/bulk_import/',
  dataType: 'json',
  contentType: 'application/json',
  data : JSON.stringify({"shared_items": [{"entity_id":"253","position":1}, {"entity_id":"823","position":2}]})
});
Run Code Online (Sandbox Code Playgroud)

在Rails中产生一个很好的对象:

Parameters: {"shared_items"=>[{"entity_id"=>"253", "position"=>1}, {"entity_id"=>"823", "position"=>2}]}
Run Code Online (Sandbox Code Playgroud)

这适用于Ruby 1.9.3中的Rails 3.

  • 想要注意的是@swajak不仅对该对象进行了字符串化,还指定了`contentType:'application/json'` (3认同)
  • 这次真是万分感谢! (2认同)
  • 考虑到从 JQuery 接收 JSON 对于 Rails 应用程序来说,这似乎不是正确的行为。对于 Rails 的这种行为,是否有合理的理由?似乎客户端 JS 代码不得不不必要地跳槽。 (2认同)

Rya*_*cox 11

稍微陈旧的问题,但我今天自己也在与之斗争,这就是我想出的答案:我相信这只是jQuery的错误,但它只是在做它自然而然的事情.但是,我确实有一个解决方法.

鉴于以下jQuery ajax调用:

$.ajax({
   type : "POST",
   url :  'http://localhost:3001/plugin/bulk_import/',
   dataType: 'json',
   data : {"shared_items": [{"entity_id":"253","position":1},{"entity_id":"823","position":2}]}

});
Run Code Online (Sandbox Code Playgroud)

jQuery将发布的值看起来像这样(如果你看看你的Firebug选择中的请求)会给你看起来像这样的表单数据:

shared_items%5B0%5D%5Bentity_id%5D:1
shared_items%5B0%5D%5Bposition%5D:1
Run Code Online (Sandbox Code Playgroud)

如果你CGI.unencode你会得到

shared_items[0][entity_id]:1
shared_items[0][position]:1
Run Code Online (Sandbox Code Playgroud)

我相信这是因为jQuery认为JSON中的那些键是表单元素名称,并且它应该将它们视为具有名为"user [name]"的字段.

所以他们进入你的Rails应用程序,Rails看到括号,并构造一个哈希来保存字段名称的最里面的键(jQuery"帮助"添加的"1").

无论如何,我通过以下方式构建我的ajax调用来解决这个问题;

$.ajax({
   type : "POST",
   url :  'http://localhost:3001/plugin/bulk_import/',
   dataType: 'json',
   data : {"data": JSON.stringify({"shared_items": [{"entity_id":"253","position":1},{"entity_id":"823","position":2}])},
  }
});
Run Code Online (Sandbox Code Playgroud)

这迫使jQuery认为这个JSON是一个你想要完全传递的,而不是它必须采用的Javascript对象,并将所有键转换为表单字段名称.

但是,这意味着Rails方面的情况略有不同,因为您需要在params [:data]中显式解码JSON.

但那没关系:

ActiveSupport::JSON.decode( params[:data] )
Run Code Online (Sandbox Code Playgroud)

TL; DR:所以,解决方案是:在你的jQuery.ajax()调用的数据参数中,{"data": JSON.stringify(my_object) }明确地做,而不是将JSON数组提供给jQuery(它错误地猜测你想用它做什么).


jes*_*nho 7

我只是碰到了这个问题,使用Rails 4.要明确地回答你的问题("为什么Rails的改变阵列到陌生的哈希?"),请参阅第4.1节滑轨上的动作控制器指导:

要发送值数组,请在键名称后附加一对空方括号"[]".

问题是,jQuery使用显式数组索引格式化请求,而不是使用空方括号.因此,例如shared_items[]=1&shared_items[]=2,它发送而不是发送shared_items[0]=1&shared_items[1]=2.Rails看到数组索引并将它们解释为散列键而不是数组索引,将请求转换为奇怪的Ruby散列:{ shared_items: { '0' => '1', '1' => '2' } }.

如果您无法控制客户端,则可以通过将哈希转换为数组来解决服务器端的此问题.我是这样做的:

shared_items = []
params[:shared_items].each { |k, v|
  shared_items << v
}
Run Code Online (Sandbox Code Playgroud)