2011-01-25 14 views
54

Puede ser que tal problema no sea nuevo, pero no encontré nada similar. Tengo dicho código jQuery:

$.ajax({ 
    url : ('/people/'+id), 
    type : 'DELETE', 
    dataType : 'json', 
    success : function(e) { 
    table.getItems(currentPage); 
    } 
}); 

controlador Mis rieles se ve así:

def destroy 
    @person = Person.find(params[:id]) 
    @person.destroy 

    respond_to do |format| 
     format.html { redirect_to(people_url) } 
     format.json { render :json => @person, :status => :ok } 
    end 
end 

Esto está funcionando.

Pero cuando se utiliza la siguiente (generado por la norma), la devolución de llamada success no recibe llamados:

def destroy 
    @person = Person.find(params[:id]) 
    @person.destroy 

    respond_to do |format| 
     format.html { redirect_to(people_url) } 
     format.json { head :ok } 
    end 
end 

probado bajo rails 3.0.3, jQuery 1.4.2 y Firefox 3.6.13.
Firebug dice, esa consulta se activa y devuelve 200 OK en ambos casos, el elemento se elimina en ambos casos también. Pero en el segundo caso, no se llama a la devolución de llamada.

¿Hay una diferencia significativa en REST, y hay una manera de utilizar jQuery utilizando el controlador scaffolded?

+0

¿Ambas solicitudes son válidas para JSON? ¿Puedes oler con Charles o golpearlos manualmente con curl y ver qué viene? –

+0

falta una cotización en su url, por las dudas. – jAndy

+0

falta qoute apareció cuando preparé el código para una pregunta :) – sandrew

Respuesta

70

Me he topado con esto varias veces y la respuesta es engañosamente simple.

Está utilizando dataType : 'json' en su llamada $ .ajax, por lo que jQuery espera una respuesta JSON. Con head :ok Rails devuelve una respuesta que contiene un espacio único (http://github.com/rails/rails/issues/1742), que jQuery no acepta como JSON válido.

Así que si realmente espera obtener un error o un encabezado 200 OK, simplemente configure dataType : 'html' en su solicitud y debería funcionar (si no establece dataType, jQuery intentará adivinar de qué tipo es basado en los encabezados de respuesta, etc., y todavía podría adivinar json, en cuyo caso todavía tendría este problema). Si realmente se espera obtener JSON, en lugar de utilizar head :ok rinden algo válido con JSON (ver comentarios) o simplemente utilizar head :no_content según lo sugerido por @Waseem

+1

¿qué harías para devolver la falla en este caso? – lulalala

+1

cabeza: servidor_servidor_interno o render: estado => 500 – Duke

+2

Una mejor manera sería usar 'head: no_content'. Ver http://stackoverflow.com/a/12751298/100466 y https://github.com/rails/rails/issues/1742 – Waseem

0

Esto a veces es causado por una versión anterior del complemento jQuery Validate. Si está utilizando este complemento, esto a veces lleva a este problema. Hay una actualización que corrige esto, si se aplica a su caso.

Por otra parte, es probable que pueda averiguar lo que va mal mediante la creación de un controlador de errores a través de:

$.ajaxSetup() o $.ajaxError()

Esto probablemente devolverá un error de análisis. Las versiones más recientes de jQuery son notorias por ser muy estrictas con respecto al análisis JSON.

+0

no, no uso plugins de jQuery (excepto algunos plugins I Me escribí a mí mismo, pero no tienen influencia para ajax). Y sé que, en el caso descrito, el servidor devuelve una respuesta vacía, y jquery, probablemente, no puede analizarlo. Y me gustaría saber si hay una forma bonita de hacerlo funcionar con esta respuesta _empty_. – sandrew

+0

Supongo que cualquier cosa que no pueda analizarse, incluida la respuesta vacía, activará la devolución de llamada ajaxError, por lo que puede configurar allí un controlador. –

6

GearHead es correcto, excepto que el analizador jQuery es en realidad lo suficientemente inteligente como para ahora trate una respuesta de cadena vacía como nula y no intente analizarla.

Sin embargo, si usted tiene las llamadas que se reciben a veces JSON y, a veces recibir una respuesta head, y que no tienen acceso al servidor o no quieren cambiar todas sus head llamadas, puede hacer esta solución alternativa:

el problema es que los carriles envía un único espacio como una respuesta vacía cuando se utiliza head (ver aquí: How to return truly empty body in rails? i.e. content-length 0)

las partes pertinentes de la mirada función jQuery parseJSON como éste en el momento de escribir estas líneas:

parseJSON: function(data) { 
    if (typeof data !== "string" || !data) { 
     return null; 
    } 

    // Make sure leading/trailing whitespace is removed (IE can't handle it) 
    data = jQuery.trim(data); 

    // Attempt to parse using the native JSON parser first 
    if (window.JSON && window.JSON.parse) { 
     return window.JSON.parse(data); 
    } 

Como puede ver, jQuery está probando si los datos son una cadena vacía antes de recortarlo. A continuación, intenta JSON.parse("") que puede ver en los resultados de la consola en un error, lo que desencadena la devolución de llamada error ajax a través de una declaración catch.

Hay una solución simple. jQuery le permite usar convertidores cuando se solicita un tipo de datos y se devuelve uno diferente. Consulte aquí para obtener más detalles: http://api.jquery.com/extending-ajax/

Dado que la respuesta de los rieles head se presenta como texto, simplemente puede definir un conversor de texto a json que recortará la respuesta antes de intentar analizarlo. Simplemente agregue este fragmento:

// deal with rails ' ' empty response 
jQuery.ajaxSetup({ 
    converters: { 
    "text json": function (response) { 
     jQuery.parseJSON($.trim(response)) 
    } 
    } 
}) 
+0

FYI, 'jQuery.parseJSON' es solo un [passthrough to' JSON.parse'] (https://github.com/jquery/jquery/blob/master/src/ajax/parseJSON.js), que arroja una excepción en una cadena vacía ("final de entrada inesperado"). Así que esto debería verificar explícitamente la respuesta vacía ('$ .trim (response) .length == 0') y' return null'. – nornagon

Cuestiones relacionadas