2012-04-12 9 views
16

Con idee uno usa before_filter :authenticate_user! para restringir el acceso solo a usuarios autenticados.¿Cómo puedo manejar elegantemente el estado 401 del diseñador en AJAX?

Cuando un no autenticado usuario intenta visitar una página restringida de todos modos, concebir de forma automática hace que una redirección a la señal en página.

Por lo tanto, intentar abrir http://localhost:3000/users/edit dará como resultado una redirección a http://localhost:3000/users/sign_in.

Ahora, si yo defino como el enlace http://localhost:3000/users/edit:remote => true, diseñar sólo se emitirá un código de estado 401 a través de JS.

Como puedo elegantemente hacer frente a esa situación y mostrar el cuadro de diálogo de inicio de sesión en una superposición O redirección como la variante no remoto lo haría?

¿Ofrece una estrategia predeterminada para esa situación que simplemente tendría que activar?

Respuesta

12

Esta es la solución que he elegido para hoy (en la sintaxis CoffeeScript):

$ -> 
    $("a").bind "ajax:error", (event, jqXHR, ajaxSettings, thrownError) -> 
    if jqXHR.status == 401 # thrownError is 'Unauthorized' 
     window.location.replace('/users/sign_in') 

Sin embargo esto (por sí mismo) solo se olvida de la página que el usuario desea visitar inicialmente, lo que limita su uso.

Se requiere una lógica adicional (controlador) para un manejo más elegante.

ACTUALIZACIÓN: redirección correcta

Dentro de la función, this sostiene la URL inicial del usuario previsto ir.

Llamando window.location.replace(this) (vez de forma explícita redirigir a la página de registro), la aplicación intentará redirigir al usuario hacia el destino previsto inicialmente.

Aunque todavía es imposible (no autorizado), ahora será una llamada GET (en lugar de JS/AJAX). Por lo tanto, Devise puede iniciar y redirigir al usuario a la página de inicio de sesión.

A partir de ahí, idearán funciona como de costumbre, reenviar al usuario a la URL de la intención original después de señal de éxito en

+0

Use esto en su lugar 'window.location.replace ('/ auth/login? Return_to =' + window.location.pathname);' –

+0

Me gustaría esta respuesta mejor si estuviera escrita en javascript y no en una forma tan asquea de escribir javascript para eventualmente compilarse a javascript. – Catfish

0

¡Estaría feliz de ver si hay una forma elegante de hacerlo también!

Hasta entonces, así es como lo he manejado.

En su archivo de vista edit.js.erb, se puede poner el siguiente el siguiente código:

<% case response.status 
    when 200 
%> 
    //do what you need to do 
<% when 401 %> 
    //handle the 401 case, for example by redirecting to root or something 
    window.location.href('/'); 
<% else %> 
    //catch all 
    alert('We\'ve had a problem, please close this, refresh the page and try again'); 
<% end %> 

que se verá en el código de estado de la respuesta y redirigir a la página de registro si se trata de 401.

Me pregunto si no hay una forma de manejar esto directamente en el nivel del controlador.

+1

Gracias por la idea. Es similar a mi enfoque actual que obtuve de esta respuesta: http://stackoverflow.com/questions/5460150/devise-with-rails-3-and-remote-true --- sin embargo, aparentemente no hay soporte erb en ese caso, lo que hace que sea imposible hacer un render o incluso solo un DRY redirigir a 'new_user_session_path' o algo similar. – user569825

1

Puede utilizar .live en el enlace de evento "ajax: error" si está haciendo ": remote => true".

$('#member_invite, #new_user') 
     .live("ajax:success", function(evt, data, status, xhr){ 
      $.colorbox.close(); 
     }) 
     .live("ajax:error", function(evt, data, status, xhr){ 
      alert("got an error"); 
     }); 

donde "#new_user" sería el valor de ID de formulario.

Tenga en cuenta que una forma más elegante si ya dispone de una plantilla o de diálogo es simplemente insertar un mensaje, así que en vez de alerta():

$('.messages').html('Invalid email or password'); 

y en su forma signin que acaba de hacer un

<div class="messages"></div> 

O simplemente podría reemplazar el título del formulario, cualesquiera que sean sus necesidades.

+0

Gracias por la sugerencia. Creo que entendiste que estoy en la página de inicio de sesión del ejemplo. Sin embargo, la pregunta es sobre tratar de acceder a un área restringida sin autenticar. Tenga en cuenta que '.live()' está en desuso en favor de '.on()' en jQuery 1.7. – user569825

14
$(document).ajaxError(function (e, xhr, settings) { 
     if (xhr.status == 401) { 
      $('.selector').html(xhr.responseText); 
     } 
    }); 
+1

Esto funcionó para mí: lo puse en un archivo .js que se llama en cada página donde tengo ajax envíos, pero reemplacé el $ ('. Selector'). Html (xhr.responseText);} con location.reload(); y esto impulsa a Devise a la vida, redirecciona a la página de inicio de sesión normal y luego de iniciar sesión vuelve a traerle – Mitch

+0

@Mitch: Sí. Eso es correcto –

2

Una versión caso de mezcla de unión con location.reload():.

$(function($) { 
    $("#new-user") 
    .bind("ajax:error", function(event, xhr, status, error) { 
     if (xhr.status == 401) { // probable Devise timeout 
     alert(xhr.responseText); 
     location.reload();  // reload whole page so Devise will redirect to signin 
     } 
    }); 
}); 

de pruebas con Devise 3.1.1, esto establece correctamente session["user_return_to"], por lo que el usuario vuelve a la página después de iniciar sesión de nuevo().

que añade el alert como una forma sencilla de abordar la cuestión mensaje poco elegante discutido aquí: Session Timeout Message in RoR using Devise

+0

Veo cómo esto puede servir como una solución a los problemas relacionados con los tiempos de espera. Sin embargo, si el formulario de inicio de sesión está en una página diferente, este código parece que no puede redirigir a él. – user569825

+0

¿Quiere decir que el formulario de inicio de sesión está en una página diferente de la página estándar? No he intentado eso. ¿'Rake rutas | grep signin' devuelve algo por ti? El mío va a 'idear/sessions # new', que creo que es el predeterminado (aunque lo tengo definido explícitamente por otros motivos). Todo lo que hace este código es volver a cargar la página base, lo que debería obligar a Devise a "** redirigir ya que la variante no remota ** lo haría." –

+1

El caso es que si el usuario" actualmente "se encuentra en una página a la que ** tiene ** acceso no autenticado, pero hace clic en un enlace a una página que ** no necesita ** para ser autenticado, la propuesta solución simplemente vuelve a cargar la página ** (!) ** actual, ya accesible. La intención permanece invisible para Devise y la sesión # nueva (o similar) no se modifica. Para cubrir ambos casos, debe redirigir a la página deseada. Ver 'location.replace' en mi respuesta. – user569825

2

Aquí está mi solución copiar-pasado-Hapy (tm) en coffeescript. Redirige todos los 401 a la página de inicio de sesión.

<% environment.context_class.instance_eval { include Rails.application.routes.url_helpers } %> 

$(document).ajaxError (_, xhr)-> 
    window.location = '<%= new_user_session_path %>' if xhr.status == 401 

y en Javascript:

<% environment.context_class.instance_eval { include Rails.application.routes.url_helpers } %> 

$(document).ajaxError(function(event, xhr){ 
    if (xhr.status == 401) { 
    window.location = '<%= new_user_session_path %>' 
    } 
}); 
Cuestiones relacionadas