Rails ne décodant pas JSON de jQuery correctement (le tableau devenant un hachage avec des clés entières)

Chaque fois que je veux poster un tableau d’objects JSON avec jQuery to Rails, j’ai ce problème. Si je ficelle le tableau, je peux voir que jQuery fait son travail correctement:

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

Mais si je viens d’envoyer le tableau comme les données de l’appel AJAX, j’obtiens:

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

Alors que si je viens d’envoyer un tableau simple, cela fonctionne:

 "shared_items"=>["entity_253"] 

Pourquoi Rails change-t-il le tableau en étrange hash? La seule raison qui me vient à l’esprit est que Rails ne peut pas comprendre correctement le contenu car il n’y a pas de type ici (y a-t-il un moyen de le définir dans l’appel jQuery?):

 Processing by SharedListsController#create as 

Je vous remercie!

Mise à jour: J’envoie les données sous forme de tableau, pas de chaîne et le tableau est créé dynamicment à l’aide de la fonction .push() . Essayé avec $.post et $.ajax , même résultat.

Si quelqu’un trébuche sur ce point et veut une meilleure solution, vous pouvez spécifier l’option “contentType: ‘application / json'” dans l’appel .ajax et faire en sorte que Rails parsing correctement l’object JSON sans le mettre dans des hachages entiers valeurs de chaîne.

Donc, pour résumer, mon problème était que ceci:

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

a conduit Rails à parsingr des choses comme:

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

alors que ceci (NOTE: nous sums en train de contraindre l’object javascript et de spécifier un type de contenu, afin que les rails sachent comment parsingr notre chaîne):

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

produit un object sympa dans Rails:

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

Cela fonctionne pour moi dans Rails 3, sur Ruby 1.9.3.

Question un peu ancienne, mais je me suis battu avec ça aujourd’hui, et voici la réponse que j’ai trouvée: Je pense que c’est un peu la faute de jQuery, mais que cela ne fait que ce qui est naturel. J’ai cependant une solution de contournement.

Compte tenu de l’appel ajax suivant de jQuery:

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

Les valeurs que jQuery affichera ressembleront à ceci (si vous regardez la demande dans votre Firebug-of-choice), vous obtiendrez des données de formulaire qui ressemblent à ceci:

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

Si vous CGI.unencode que vous aurez

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

Je crois que c’est parce que jQuery pense que ces clés dans votre JSON sont des noms d’éléments de formulaire, et qu’il devrait les traiter comme si vous aviez un champ nommé “utilisateur [nom]”.

Donc, ils entrent dans votre application Rails, Rails voit les crochets et construit un hachage pour contenir la clé la plus interne du nom du champ (le “1” que jQuery a “utilement” ajouté).

En tout cas, j’ai contourné ce comportement en construisant mon appel ajax de la façon suivante;

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

Ce qui oblige jQuery à penser que ce JSON est une valeur que vous voulez passer entièrement, et non un object Javascript qu’il doit prendre et transformer toutes les clés en noms de champs de formulaire.

Cependant, cela signifie que les choses sont un peu différentes du côté Rails, car vous devez décoder explicitement le JSON dans les parameters [: data].

Mais ça va:

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

TL; DR: Donc, la solution est la suivante: dans le paramètre data de votre appel jQuery.ajax (), faites {"data": JSON.ssortingngify(my_object) } explicitement, au lieu d’alimenter le tableau JSON dans jQuery (où il devine à tort ce que vous voulez en faire.

Je viens de rencontrer ce problème avec Rails 4. Pour répondre explicitement à votre question (“Pourquoi Rails change-t-il le tableau en hash étrange?”), Consultez la section 4.1 du guide Rails sur les contrôleurs d’action :

Pour envoyer un tableau de valeurs, ajoutez une paire vide de crochets “[]” au nom de la clé.

Le problème est que jQuery formate la requête avec des index de tableau explicites, plutôt qu’avec des crochets vides. Ainsi, par exemple, au lieu d’envoyer shared_items[]=1&shared_items[]=2 , il envoie shared_items[0]=1&shared_items[1]=2 . Rails voit les indices du tableau et les interprète comme des clés de hachage plutôt que comme des index de tableaux, transformant la requête en un hash Ruby étrange: { shared_items: { '0' => '1', '1' => '2' } } .

Si vous n’avez pas le contrôle du client, vous pouvez résoudre ce problème du côté serveur en convertissant le hachage en un tableau. Voici comment je l’ai fait:

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

méthode suivante pourrait être utile si vous utilisez des parameters forts

 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 

Avez-vous envisagé de faire parsed_json = ActiveSupport::JSON.decode(your_json_ssortingng) ? Si vous envoyez des .to_json à l’ .to_json vous pouvez utiliser .to_json pour sérialiser les données.

Essayez-vous simplement de placer la chaîne JSON dans une action du contrôleur Rails?

Je ne suis pas sûr de ce que Rails fait avec le hachage, mais vous pouvez contourner le problème et avoir plus de chance en créant un object Javascript / JSON (par opposition à une chaîne JSON) et en l’envoyant comme paramètre de données pour votre Ajax. appel.

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

Si vous vouliez envoyer ceci via ajax, alors vous feriez quelque chose comme ceci:

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

Notez qu’avec l’extrait ajax ci-dessus, jQuery fera une supposition intelligente sur le dataType, bien qu’il soit généralement bon de le spécifier explicitement.

De toute façon, dans l’action de votre contrôleur, vous pouvez obtenir l’object JSON que vous avez passé avec le hachage params, c’est-à-dire

 params[:shared_items] 

Par exemple, cette action va vous renvoyer votre object json:

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

Utilisez le gem rack-jquery-params (avertissement: je suis l’auteur). Il corrige votre problème de tableaux devenant des hachages avec des clés entières.