2011-06-20 20 views
82

每次我想用jQuery將Rails的JSON對象數組發送到Rails時,我遇到了這個問題。 如果我字符串化數組我可以看到,jQuery是做正確的工作:Rails無法正確解碼json的JSON(數組成爲整數鍵的散列)

"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,結果相同。

回答

148

如果有人遇到這種情況並希望有更好的解決方案,可以在.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對象和指定內容類型,以便導軌知道如何解析我們的字符串):

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

這適用於我在Rails 3,在Ruby 1.9.3上。

+2

謝謝! – jwarzech

+0

這個答案優於所選的答案。讓我們把它放到頂端! –

+0

接受這一點,因爲這是什麼Rails真的需要與JSON正常工作。 如果您使用RSpec/Cucumber測試JSON Rails API,則必須採取類似的措施。 RSpec:設置'@ request.env ['HTTP_ACCEPT'] =「application/json」'。黃瓜:在標頭中傳遞''HTTP_ACCEPT'=>'application/json''。 – aledalgrande

0

你有沒有考慮過做parsed_json = ActiveSupport::JSON.decode(your_json_string)?如果您以其他方式發送內容,則可以使用.to_json來串行化數據。

+1

是的考慮過,但想知道是否有一個「正確的方法」在Rails中做到這一點,而無需手動編碼/解碼。 – aledalgrande

0

你只是想讓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將做出明智的猜測對具體的數據類型,但它通常是很好的明確指定它。

無論哪種方式,在你的控制器動作,你可以得到你params哈希表通過JSON對象,即

params[:shared_items] 

例如今天

def reply_in_json 
    @shared = params[:shared_items] 

    render :json => @shared 
end 
+0

謝謝,但這正是我現在正在做的(請參閱更新),它不起作用。 – aledalgrande

11

略顯陳舊的問題,但我用這個打我,這裏是我想出了答案:這個動作會吐出你的JSON對象回你相信這是稍微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這些鍵是表單元素的名字,它應該對待他們,如果你有一個名爲「用戶[名]」字段。

於是,他們走進你的Rails應用程序時,Rails看到支架,構建一個散列保持字段名的最裏面的鍵(「1」,即「有益補充說:」 jQuery的)。

反正我解決此問題,通過構建我的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對象,它必須參加並把所有的鑰匙到表單字段名稱。

然而,這意味着東西都在鐵軌上側有一點不同,因爲你需要在PARAMS明確解碼JSON [:數據]。

但是沒關係:

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

TL; DR:所以,解決的辦法是:在數據參數,以此來jQuery.ajax()調用,做{"data": JSON.stringify(my_object) }明確,而不是餵養的JSON數組到jQuery中(它猜錯了你想要做的事情)

+0

沒有更新,但這就是我所做的。 – aledalgrande

+0

從@swajak下面找到更好的解決方案。 –

5

我只是碰到了這個問題,使用Rails 4.要明確地回答你的問題(「爲什麼Rails的改變陣列到陌生的哈希?」),見第4節。的1 Rails guide on Action Controllers

To send an array of values, append an empty pair of square brackets "[]" to the key name.

問題是,jQuery的格式與顯式陣列索引,而不是與空方括號中的請求。因此,例如,它不發送shared_items[]=1&shared_items[]=2,而是發送shared_items[0]=1&shared_items[1]=2。 Rails看到數組索引並將它們解釋爲散列鍵而不是數組索引,從而將請求轉變爲一個奇怪的Ruby散列:{ shared_items: { '0' => '1', '1' => '2' } }

如果您沒有客戶端的控制權,可以通過將散列轉換爲數組來解決服務器端的問題。以下是我做的:如果你使用強大的參數

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 
1

下面的方法可能會有所幫助。它修復了用整數鍵變成散列的數組問題。

0

使用rack-jquery-params寶石(:我是作者聲明)

shared_items = [] 
params[:shared_items].each { |k, v| 
    shared_items << v 
} 
+0

更好地提供一些代碼片段,而不是放置鏈接 – VicJordan