remote rails form_tag example and jquery ruby-on-rails arrays json post

jquery - form_tag - ruby on rails ajax example



Rieles que no descodifican JSON de jQuery correctamente(la matriz se convierte en un hash con claves enteras) (7)

Cada vez que quiero enviar una matriz de objetos JSON con jQuery a Rails, tengo este problema. Si he stringify la matriz, puedo ver que jQuery está haciendo su trabajo correctamente:

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

Pero si solo envío la matriz como los datos de la llamada AJAX que obtengo:

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

Mientras que si solo envío una matriz simple funciona:

"shared_items"=>["entity_253"]

¿Por qué Rails está cambiando la matriz a ese extraño hash? La única razón que me viene a la mente es que Rails no puede entender correctamente los contenidos porque aquí no hay ningún tipo (¿hay alguna forma de configurarlo en la llamada a jQuery?):

Processing by SharedListsController#create as

¡Gracias!

Actualización: envío los datos como una matriz, no como una cadena, y la matriz se crea dinámicamente con la función .push() . Intenté con $.post y $.ajax , el mismo resultado.


¿Estás tratando de poner la cadena JSON en una acción de controlador de Rails?

No estoy seguro de lo que Rails está haciendo con el hash, pero puede solucionar el problema y tener más suerte al crear un objeto JavaScript / JSON (a diferencia de una cadena JSON) y enviarlo como el parámetro de datos para su Ajax llamada.

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

Si quisiera enviar esto a través de ajax, entonces haría algo como esto:

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

Tenga en cuenta que con el fragmento ajax anterior, jQuery hará una suposición inteligente sobre el tipo de datos, aunque generalmente es bueno especificarlo explícitamente.

De cualquier manera, en la acción de su controlador, puede obtener el objeto JSON que aprobó con hash de parámetros, es decir,

params[:shared_items]

Por ejemplo, esta acción te escupirá tu objeto json:

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


¿Ha considerado hacer parsed_json = ActiveSupport::JSON.decode(your_json_string) ? Si envía material al revés, puede usar .to_json para serializar los datos.


Acabo de toparme con este problema con Rails 4. Para responder explícitamente a su pregunta ("¿Por qué Rails está cambiando la matriz a ese hash extraño?"), Consulte la sección 4.1 de la guía Rails sobre Action Controllers :

Para enviar una matriz de valores, agregue un par de corchetes vacíos "[]" al nombre de la tecla.

El problema es que jQuery formatea la solicitud con índices de matriz explícitos, en lugar de hacerlo con corchetes vacíos. Por lo tanto, por ejemplo, en lugar de enviar elementos shared_items[]=1&shared_items[]=2 , envía shared_items[0]=1&shared_items[1]=2 . Rails ve los índices de matriz y los interpreta como claves hash en lugar de índices de matriz, convirtiendo la solicitud en una extraña hash Ruby: { shared_items: { ''0'' => ''1'', ''1'' => ''2'' } } .

Si no tiene control del cliente, puede solucionar este problema en el servidor convirtiendo el hash en una matriz. Así es como lo hice:

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


El siguiente método podría ser útil si usa parámetros potentes

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


En caso de que alguien se tropiece con esto y quiera una solución mejor, puede especificar la opción "contentType: ''application / json''" en la llamada .ajax y hacer que Rails analice correctamente el objeto JSON sin engrosarlo en hashes de código entero con all- valores de cadena

Entonces, para resumir, mi problema fue que esto:

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

dio lugar a que Rails analizara las cosas como:

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

mientras que esto (NOTA: ahora estamos codificando el objeto javascript y especificando un tipo de contenido, para que los raíles sepan cómo analizar nuestra cadena):

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

resulta en un buen objeto en Rails:

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

Esto funciona para mí en Rails 3, en Ruby 1.9.3.


Una pregunta un poco vieja, pero luché con esto yo mismo hoy, y aquí está la respuesta que se me ocurrió: creo que esto es un poco culpa de jQuery, pero que solo está haciendo lo que es natural para él. Sí, tengo una solución alternativa.

Dada la siguiente llamada 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}]} });

Los valores que jQuery publicará tendrán el siguiente aspecto (si mira la Solicitud en su Firebug de elección) le dará datos de formulario que se verán así:

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

Si CGI.unencode que obtendrá

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

Creo que esto se debe a que jQuery piensa que esas claves en su JSON son nombres de elementos de formulario, y que debería tratarlos como si tuviera un campo llamado "usuario [nombre]".

De modo que entran en la aplicación de Rails, Rails ve los corchetes y construye un hash para mantener la clave más interna del nombre del campo (el "1" que jQuery "amablemente" agregó).

De todos modos, solucioné este comportamiento construyendo mi llamada ajax de la siguiente manera;

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

Lo que obliga a jQuery a pensar que este JSON es un valor que desea pasar, en su totalidad, y no un objeto Javascript, debe tomar y convertir todas las claves en nombres de campo de formulario.

Sin embargo, eso significa que las cosas son un poco diferentes en el lado de Rails, porque necesita decodificar explícitamente el JSON en params [: data].

Pero eso esta bien:

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

TL; DR: Entonces, la solución es: en el parámetro de datos a su llamada jQuery.ajax (), haga {"data": JSON.stringify(my_object) } explícitamente, en lugar de alimentar la matriz JSON en jQuery (donde adivina erróneamente lo que quieres hacer con eso.


Use la gema rack-jquery-params (descargo de responsabilidad: soy el autor). Soluciona el problema de que las matrices se conviertan en hashes con claves enteras.