2011-05-22 6 views
9

Estoy tratando de reemplazar el contenido de un div después de hacer clic en un enlace usando Rails 3, remote_link :remote => true y jQuery.Error del analizador cuando se usa jQuery-UJS para el enlace remoto a la aplicación Rails 3: ¿cómo puedo depurar esto?

Hasta ahora, he podido hacer que el controlador muestre el parcial correcto mientras responde con un código HTTP 200. He puesto algunas devoluciones de llamada para encontrar el origen del problema:

jQuery(function($) { 
    $("#follow-link").bind("ajax:before", function() { 
     console.log("ajax:before"); 
    }); 

    $("#follow-link").bind("ajax:success", function(data, status, xhr) { 
     console.log("ajax:success"); 
    }); 

    $("#follow-link").bind("ajax:complete", function() { 
     console.log("ajax:complete"); 
    }); 

    $("#follow-link").bind("ajax:error", function(xhr, status, error) { 
     console.log("ajax:error"); 
     console.log(error); 
    }); 
}); 

Mientras before y complete se disparan, no es successerror y salidas "parsererror". El contenido que obtengo cuando inspecciono la respuesta en las herramientas de desarrollo de Safari es una cadena simple.

¿Por qué generaría un parsererror? ¿Cómo puedo obtener más información sobre qué está causando este error?

+2

Como se trata de un error de análisis, ¿podría estar esperando JSON o XML y conseguir HTML, o algo por el estilo? Si buscas en Recursos en Safari, puedes examinar la respuesta. No has mostrado la llamada Ajax, por lo que es difícil saber qué está pasando. Se supone que jQuery "adivina" el tipo de respuesta en función del tipo MIME; es difícil saber dónde podría salir mal, pero vale la pena mirar la respuesta para asegurarse de que está enviando las mismas cosas que su servidor declara en el tipo MIME. –

+0

En el encabezado del recurso, la solicitud está configurada para aceptar 'text/javascript' y la respuesta también es' text/javascript'. La llamada es 'Unfollow' generada por Rails helper 'link_to" Follow ", follow_path (usuario),: remote => true,: id =>" follow-link "'. –

+1

Entonces estás usando 'rails.js'. No estoy seguro de lo que está obteniendo en la "cadena simple" o qué tipo de MIME es. Muy claramente, jQuery está intentando analizar esto o lo está entregando al motor js de Safari para analizarlo como script. De cualquier manera, ese no es el efecto deseado, ¿verdad? Mire en la pestaña de Recursos y en el parcial debe aparecer cerca de la parte inferior. Luego, cuando veas la cadena que fue devuelta, ¿qué es eso? Además, haga clic en la pestaña de encabezados de la ventana de visualización y observe el encabezado Solicitar aceptación y el encabezado Tipo de contenido de respuesta. Estos deberían darle una idea de lo que pasa. –

Respuesta

3

Voy a proponer una respuesta porque los comentarios no permiten ningún formato. Aquí está: algo está sucediendo en el lado del servidor y jQuery no está obteniendo lo que crees que es. He aquí un extracto de la documentación de jQuery:

error (jqXHR, textStatus, errorThrown) Función Una función ser llamados si la petición falla. La función recibe tres argumentos: El jqXHR (en jQuery 1.4.x, XMLHttpRequest) objeto, una cadena describe el tipo de error que se produjo y un objeto opcional excepción , si se dio. Los valores posibles para el segundo argumento (además de nulo) son "tiempo de espera", "error", "abortar" y "parsererror". Cuando se produce un error HTTP , errorThrown recibe la parte textual del estado HTTP , como "No encontrado" o "Error interno del servidor".

Eso implica que su controlador puede estar respondiendo con algo que no sea los datos esperados. En ese controlador, intente:

Rails.logger.debug render_to_string(:partial => "followings/follow") 

En cualquier caso, revisar sus registros para asegurarse de que lo que usted piensa que está sucediendo realmente está sucediendo. Además, escriba una prueba para comprobar esto:

# controller spec... modify if using Test::Unit 
it "sends cool javascript" do 
    xhr.post :unfollow, :id => 83, :data-method => "delete" 
    response.body should == "some known response" 
end 

Ok, es una especificación hacky, frágil, pero lo hará hasta que no sepa donde las cosas van mal.

Una vez que funcione, todo lo demás se ajustará perfectamente.

+3

El problema era que estaba usando 'format.js' en lugar de' format.html' en el controlador para representar un html parcial. Todavía no sé por qué renderizar el html parcial dentro de un js rompería todo, pero ahora está funcionando. –

+1

jQuery le pasa el script al navegador para evaluar. Debería ser imposible de analizar. –

+0

¡Excelente! estos comentarios resolvieron mi problema :) –

12

También conseguía extraña parsererror s aunque mis enlaces remotos estaban apuntando correctamente a las acciones con :format => :js y mis acciones del controlador fueron correctamente utilizando respond_to para servir objetos JSON como:

respond_to do |format| 
    format.js do 
    render :json => {:something => "OK"} 
    end 
end 

La solución terminó siendo simplemente dejar caer esta línea en mi application.js:

$.ajaxSettings.dataType = "json"; 

Por defecto, parecía que estaba tratando de jQuery para evaluar todas las respuestas como "script", que me adivinar significa que estaba tratando de ejecutarlo como código-? Dejar caer esta línea una vez solucionado el problema globalmente.

+3

Configuración '$ .ajaxSettings.dataType = 'json';' resolvió el problema 'parsererror' también. Sin embargo, no sé por qué esto es necesario. – nickh

+0

La razón por la que se necesita es porque por defecto rails.js (o tal vez jQuery, no estoy seguro en realidad) está solicitando texto/javascript (: js) en lugar de application/json (: json) y no puede analizar porque JSON no es válido JavaScript por sí mismo. Tenga en cuenta que necesita actualizar format.js para format.json cuando hace esto también, aunque en este ejemplo simple funciona porque solo hay un bloque que cuenta como predeterminado. – gtd

0

La solución para mí fue también reemplazar el formato de respuesta con '.html' en lugar de '.js' en el controlador.

Lo que hace es enviar el tipo de contenido de respuesta como "html/text" en lugar de "html/javascript", y esto, de alguna manera es aceptable para el analizador de respuestas.

1

en lugar de format.js uso format.json

establecer $.ajaxSettings.dataType = 'json'; es susceptible de causar problemas en otras partes de su código.

5

En lugar de utilizar la configuración global $.ajaxSettings.dataType = 'json';, una solución limpiadora es agregar un atributo data-type al elemento de formulario. Los controladores de eventos de forma remota pasarán a través de este como el tipo de datos a la llamada jQuery AJAX, por ejemplo:

form_for @subject, :remote => true, :html => {'data-type' => 'json'} 
+0

Esto es exactamente lo que necesitaba. Mucho más limpio que establecer globalmente o usar ajax: completo. –

0

Otra manera de resolver esto es agregar Js a la acción de la forma (si está usando un enlace rieles generador que puede agregar: format =>: json). Luego, asegúrese de estar respondiendo a json en su controlador.

He aquí un ejemplo de una señal en forma configurado de esa manera:

<%= form_for User.new, :url => session_path(:user, :format => :json), :html => {:id => "login-form", :class => "well"}, :remote => :true do |f| %> 
     <label>Email</label> 
     <%= f.text_field :email %> 
     <label>Password</label> 
     <%= f.password_field :password %> 
     <%= f.hidden_field :remember_me %> 
     <%= button_tag "Sign in", :class => "btn", :type => "submit" %><%= image_tag "ajax-loader.gif", :style => "display:none", :id => "login-spinner" %> 
    <% end %> 

En el controlador:

def create 
respond_to do |format| 
    format.html{ super } 
    format.json do 
    resource = warden.authenticate!(:scope => resource_name, :recall => :failure) 
    return sign_in_and_redirect(resource_name, resource) 
    end 
end 
end 
0

Si está intentando actualizar el contenido de un DIV utilizando una normal de jQuery AJAX llamada usando la salida HTML de una acción de controlador de rieles, necesita decirle a JQuery qué tipo de datos esperar de la respuesta, para que no analice la respuesta como javascript y le proporcione el error parserer que usted describe.

$.ajax({ url: "/blah", 
    contentType: "text/javascript", dataType: "html", 
    beforeSend: function(xhr) { 
    xhr.setRequestHeader('Accept', 'text/javascript');  
    }, 
    success: function(data) { 
    $('your-div').html(data); 
    } 
}); 

Esto entonces ser compatible con una acción de controlador que utiliza el bloque respond_to:

respond_to do |format| 
    format.html { 
    # This would be a normal render of your template. 
    } 
    format.js { 
    # This would be a render of your template, as HTML, but only for your AJAX requests. 
    # We might use this to avoid including the layout of our template. 
    render :layout => nil 
    } 
end 
Cuestiones relacionadas