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(声明:我是作者)。 它修复了您的数组变成散列整数键的问题。