91 votes

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


chaque fois que je veux poster un tableau d'objets JSON avec jQuery pour les Rails, j'ai ce problème. Si je stringify le tableau je vois que jQuery est en train de faire son travail correctement:

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

Mais si je viens d'envoyer le tableau que 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 simple tableau il fonctionne:

"shared_items"=>["entity_253"]

Pourquoi est-Rails de changer le tableau de cette étrange hachage? La seule raison qui vient à l'esprit est que les Rails ne pouvez pas comprendre correctement le contenu, car il n'y a pas de type ici (est-il un moyen de le mettre dans le jQuery appel?):

Le traitement par SharedListsController#créer

Merci!!!!

Mise à jour: J'envoie les données dans un tableau, pas une chaîne de caractères et le tableau est créé dynamiquement à l'aide de l' .push() fonction. Essayé avec $.poste et $.ajax, le même résultat.

169voto

swajak Points 953

Dans le cas où quelqu'un tombe sur ce et souhaite une meilleure solution, vous pouvez spécifier la "contentType:" application/json"," option dans l' .appel ajax et Rails analyser correctement l'objet JSON sans fausser en entier assortie de hachages avec toutes les valeurs de chaîne.

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

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

entraîné dans les Rails de l'analyse des choses comme:

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

alors que cette (NOTE: nous sommes toujours stringifying l'objet javascript, la différence est que les rails analyser cette chaîne avec succès maintenant):

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

résultats dans un bel objet dans les 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.

13voto

RyanWilcox Points 7838

Légèrement vieille question, mais je me suis battu avec moi-même aujourd'hui, et voici la réponse que j'ai trouvé: je crois que c'est un peu de jQuery faute, mais qu'il ne fait que ce qui est naturel. Je ne, cependant, ont une solution de contournement.

Compte tenu de la suite de jQuery ajax composez le:

$.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 jQuery publierons va ressembler à quelque chose comme ceci (si vous regardez à la Demande dans votre Firebug de choix) vous donnera les données de formulaire qui ressemble à ceci:

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

Si vous CGI.unencode que vous obtiendrez

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 de forme des noms d'éléments, et qu'il doit les traiter comme si vous aviez un champ nommé "user[nom]".

Donc, ils viennent dans votre application Rails, Rails voit les crochets, et construit une table de hachage pour tenir le plus profond de la clé du nom du champ (le "1" jQuery "utilement", a ajouté).

De toute façon, j'ai eu autour de ce problème par la construction de mon appel ajax de la manière suivante;

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

Qui des forces de jQuery à penser que cette JSON est une valeur que vous souhaitez passer, tout à fait, et pas un objet Javascript doit tenir et tourner toutes les clés dans les noms de champ de formulaire.

Toutefois, cela signifie que les choses sont un peu différentes sur les Rails de côté, parce que vous devez explicitement décoder le JSON dans params[:données].

Mais c'est OK:

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

TL;DR: Donc, la solution est la suivante: dans le paramètre data de votre jQuery.ajax() de l'appel, effectuez l' {"data": JSON.stringify(my_object) } explicitement, au lieu de nourrir le tableau JSON en jQuery (où l'on devine, à tort, ce que vous voulez faire avec elle.

7voto

jessepinho Points 175

Je viens de tomber sur cette question avec des Rails 4. Explicitement de répondre à votre question ("Pourquoi est-Rails de changer le tableau de cette étrange hachage?"), voir la section 4.1 du guide Rails sur les Contrôleurs d'Action:

Pour envoyer un tableau de valeurs, d'ajouter un vide paire de crochets "[]" au nom de la clé.

Le problème est, jQuery formats à la demande expresse des index de tableau, plutôt que de vides entre crochets. Ainsi, par exemple, au lieu de l'envoi d' shared_items[]=1&shared_items[]=2, il envoie shared_items[0]=1&shared_items[1]=2. Rails voit les index du tableau et les interprète comme des clés de hachage plutôt que des index de tableau, en tournant la demande dans un drôle de Ruby hash: { shared_items: { '0' => '1', '1' => '2' } }.

Si vous n'avez pas le contrôle du client, vous pouvez résoudre ce problème sur le serveur par la conversion de la valeur de hachage d'un tableau. Voici comment j'ai fait:

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

0voto

Michael de Silva Points 2914

Avez-vous envisagé de faire parsed_json = ActiveSupport::JSON.decode(your_json_string) ? Si vous envoyez des choses dans l'autre sens, vous pouvez utiliser .to_json pour sérialiser les données.

0voto

australis Points 331

Êtes-vous juste essayer d'obtenir de la chaîne JSON dans un Rails de contrôleur de l'action?

Je ne suis pas sûr de ce que les Rails sont en train de faire avec la table de hachage, mais vous pouvez contourner le problème et d'avoir plus de chance par la création d'un Javascript/JSON en objet (par opposition à une chaîne JSON) et de l'envoyer à travers le paramètre de données pour votre appel Ajax.

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

Si vous vouliez envoyer via ajax alors vous devez faire 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);
    }
});

Remarque avec l'ajax extrait ci-dessus, jQuery va faire un intelligent suppose que sur le type de données, mais il est généralement bon de le spécifier explicitement.

De toute façon, dans les actions de votre contrôleur, vous pouvez obtenir l'objet JSON que vous avez passé avec les params de hachage, c'est à dire

params[:shared_items]

E. g. cette action va cracher votre objet json de retour à vous:

def reply_in_json
  @shared = params[:shared_items]

  render :json => @shared
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X