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

每次我想用jQuery将Rails的JSON对象数组发送到Rails,我有这个问题。 如果我string数组,我可以看到,jQuery正在正常工作:

"shared_items"=>"[{\"entity_id\":\"253\",\"position\":1},{\"entity_id\":\"823\",\"position\":2}]" 

但是,如果我只是发送数组作为AJAX调用的数据,我得到:

 "shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}} 

而如果我只是发送一个普通的数组,它的作品:

 "shared_items"=>["entity_253"] 

为什么Rails将数组更改为奇怪的散列? 想到的唯一原因是Rails无法正确理解内容,因为这里没有types(是否有方法在jQuery调用中设置它):

 Processing by SharedListsController#create as 

谢谢!

更新:我将数据作为数组发送,而不是string,并使用.push()函数dynamic创build数组。 尝试与$.post$.ajax ,相同的结果。

如果有人遇到这个问题,并希望得到更好的解决scheme,可以在.ajax调用中指定“contentType:'application / json'”选项,并让Rails正确parsingJSON对象,而不是将其用all-string值。

所以,总结一下,我的问题是这样的:

 $.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}]} }); 

导致Railsparsing的东西是:

 Parameters: {"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}} 

而这(注意:现在我们正在对javascript对象进行string化并指定一个内容types,所以rails会知道如何parsing我们的string):

 $.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}]}) }); 

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

 Parameters: {"shared_items"=>[{"entity_id"=>"253", "position"=>1}, {"entity_id"=>"823", "position"=>2}]} 

这在Ruby 1.9.3中适用于Rails 3。

稍微老一点的问题,但我今天自己与这个问题进行了斗争,下面是我提出的答案:我相信这是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}]} }); 

jQuery将发布的值看起来像这样(如果你看看你的Firebug中的请求)将给你的表单数据,如下所示:

 shared_items%5B0%5D%5Bentity_id%5D:1 shared_items%5B0%5D%5Bposition%5D:1 

如果你CGI.unencode你会得到

 shared_items[0][entity_id]:1 shared_items[0][position]:1 

我相信这是因为jQuery认为你的JSON中的这些键是表单元素的名称,并且应该把它们看作你有一个名为“user [name]”的字段。

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

无论如何,我通过构build我的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}])}, } }); 

这迫使jQuery认为这个JSON是一个你想要传递的 ,而不是一个Javascript对象,它必须把所有的键都转换成表单字段名。

但是,这意味着Rails方面的东西有点不同,因为你需要在params [:data]中显式解码JSON。

但没关系:

 ActiveSupport::JSON.decode( params[:data] ) 

TL; DR:所以,解决的办法是:在你的jQuery.ajax()调用的数据参数中,显式地执行{"data": JSON.stringify(my_object) } ,而不是将JSON数组提供给jQuery错了,你想用它做什么。

我刚刚遇到了Rails 4的这个问题。要明确地回答你的问题(“为什么Rails将数组改成奇怪的哈希?”),请参阅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 } 

你有没有考虑过做parsed_json = ActiveSupport::JSON.decode(your_json_string) ? 如果你正在发送的东西,你可以使用.to_json来串行化数据。

你只是想让JSONstring进入Rails控制器的行动?

我不确定Rails是如何处理这个散列的,但是你可以通过创build一个Javascript / JSON对象(而不是JSONstring)并且把它作为你的Ajax的数据参数发送呼叫。

 myData = { "shared_items": [ { "entity_id": "253", "position": 1 }, { "entity_id": "823", "position": 2 } ] }; 

如果你想通过ajax发送这个,那么你会这样做:

 $.ajax({ type: "POST", url: "my_url", // be sure to set this in your routes.rb data: myData, success: function(data) { console.log("success. data:"); console.log(data); } }); 

注意上面的ajax代码片断,jQuery将对dataType进行智能猜测,尽pipe通常明确地指定它是很好的。

无论哪种方式,在你的控制器动作,你可以得到你使用params散列传递的JSON对象,即

 params[:shared_items] 

例如这个动作会把你的json对象吐在你身上:

 def reply_in_json @shared = params[:shared_items] render :json => @shared end 

如果您使用强参数,以下方法可能会有所帮助

 def safe_params values = params.require(:shared_items) values = items.values if items.keys.first == '0' ActionController::Parameters.new(shared_items: values).permit(shared_items: [:entity_id, :position]).require(:shared_items) end 

使用rack-jquery-params gem(声明:我是作者)。 它修复了您的数组变成散列整数键的问题。