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

每次我想用jQuery向Jails发布一个JSON对象数组时,我就遇到了这个问题。如果我对数组进行字符串化,我可以看到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无法正确理解内容,因为这里没有类型(有没有办法在jQuery调用中设置它?):

Processing by SharedListsController#create as 

谢谢!

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

aledalgrande asked 2019-09-09T17:52:43Z
7个解决方案
161 votes

如果有人偶然发现并想要一个更好的解决方案,你可以在.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}]}
});

导致Rails将事物解析为:

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

而这(注意:我们现在正在对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}]})
});

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

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

这适用于Ruby 1.9.3中的Rails 3。

swajak answered 2019-09-09T17:53:27Z
11 votes

稍微陈旧的问题,但我今天自己也在与之斗争,这就是我想出的答案:我相信这只是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”)。

无论如何,我通过以下方式构建我的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(它错误地猜测你想用它做什么)。

RyanWilcox answered 2019-09-09T17:54:56Z
6 votes

我刚刚使用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
}
jessepinho answered 2019-09-09T17:55:41Z
1 votes

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

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
Eugene answered 2019-09-09T17:56:06Z
0 votes

你考虑过做parsed_json = ActiveSupport::JSON.decode(your_json_string)吗? 如果您以相反的方式发送内容,可以使用.to_json来序列化数据。

Michael De Silva answered 2019-09-09T17:56:31Z
0 votes

您是否只是尝试将JSON字符串转换为Rails控制器操作?

我不确定Rails正在使用哈希做什么,但你可以通过创建一个Javascript / JSON对象(而不是一个JSON字符串)来解决问题并获得更多运气,并将其作为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进行智能猜测,尽管明确指定它通常也是好的。

无论哪种方式,在您的控制器操作中,您都可以使用params哈希获取传递的JSON对象,即

params[:shared_items]

例如。 这个动作会把你的json对象吐回来:

def reply_in_json
  @shared = params[:shared_items]

  render :json => @shared
end
australis answered 2019-09-09T17:57:29Z
0 votes

使用rack-jquery-params gem(免责声明:我是作者)。 它修复了数组变为带整数键的哈希的问题。

Caleb Clark answered 2019-09-09T17:57:54Z
translate from https://stackoverflow.com:/questions/6410810/rails-not-decoding-json-from-jquery-correctly-array-becoming-a-hash-with-intege