2012-01-09 13 views
8

He estado usando Devise y confiando en last_sign_in_at del modelo de usuario para determinar si mis clientes no han regresado en X días. Sin embargo, recientemente descubrí que last_sign_in_at solo se actualiza cuando se produce un evento de registro de formulario real, en oposición a cuando un usuario inicia sesión automáticamente debido a la inclusión de rememberable.Idea: rememberable significa que last_sign_in_at no se ha actualizado rastreable

Si desea asegurarse de que last_sign_in_at se actualiza cada vez que un usuario inicia sesión (una nueva sesión del navegador), independientemente de si utilizaron un formulario para iniciar sesión o si ingresaron automáticamente con la cookie rememberable, ¿cómo procedería? haciendo esto de una manera compatible con Devise?

Respuesta

5

El gancho rastreable es del gancho Warden's after_set_user - lo que podría hacer para remediar fácilmente esto es establecer un before_filter para llamar al sign_in.

Esto puede ser optimizado, pero prueba para ver si el uso de

before_filter proc{ sign_in(current_user, :force => true) } 

actualiza la marca de tiempo last_signed_in_at.

+1

¿Cuándo se llama al before_filter? Espero no en cada solicitud, y solo antes de la autenticación por primera vez esa sesión? Además, pregunta estúpida, pero ¿dónde agrego before_filter? Intenté agregarlo al modelo de usuario de Devise y obtuve el método undefined before_filter. –

+0

Eso se ejecutaría en cada solicitud; era solo un paso de depuración rápido/sucio para ver si eso lo resolvería antes de implementar una mejor solución. Debería poder agregarlo a cualquier controlador, ApplicationController si lo quiere global. – RobH

+3

Hola Rob, esto es lo que hice al final que a) comprueba que un usuario está conectado antes de forzar un signo_in, yb) asegura que el método sign_in (forzado) solo se ejecuta una vez por sesión.(disculpe el; en lugar de saltos de línea, los comentarios no permiten saltos de línea) 'before_filter proc {if user_signed_in? && session [: logged_signin]; sign_in (current_user,: force => true); session [: logged_signin] = verdadero; end} ' –

13

Tomando solución de Mateo, creo que el código debe ser el siguiente (tenga en cuenta la no-operador antes de la sesión [: logged_signin]):

before_filter :update_last_sign_in_at 

protected 

def update_last_sign_in_at 
    if user_signed_in? && !session[:logged_signin] 
    sign_in(current_user, :force => true) 
    session[:logged_signin] = true 
    end 
end 
+0

¿Es esta la mejor solución hasta ahora? –

+0

Lo tengo. Está utilizando un parámetro de cookie personalizado para comprobar si se trata de una sesión nueva o existente. Gracias por la sugerencia, esto se siente como un enfoque mucho más limpio en mi caso, ya que significa que no tengo que profundizar en las partes internas de Devise. –

-1

que sabemos, se puede usar también update_tracked_fields! en ese modelo current_user.

+0

'update_tracked_fields!' Toma la solicitud como parámetro. Desde el dispositivo también rastrea IP. Simplemente haga esto en el controlador, 'current_user.update_tracked_fields! (Request)'. –

2

Devise: rememberable means that last_sign_in_at is not updated by trackable

Ampliando soluciones anteriores, el problema con ellos sería que si el usuario inicia sesión normalmente, van a "firmar en dos ocasiones". Que establecerá last_sign_in_at en el mismo valor (o casi el mismo) que current_sign_in_at. En mi sitio, uso last_sign_in_at para que el usuario sepa qué pasó desde la última vez que visitó el sitio y, como tal, necesito que sea un tanto preciso. Además, registra +1 inicio de sesión.

Además, hay personas (como yo) que dejan una ventana del navegador abierta durante días sin cerrarla (y por lo tanto nunca borran la marca de la sesión). Para fines métricos, etc., puede ser útil si dicho comportamiento del usuario a veces actualiza el tiempo current_sign_in_at.

Las siguientes variantes remediarán estas cosas.

class ApplicationController < ActionController::Base 
    before_filter :update_sign_in_at_periodically 
    UPDATE_LOGIN_PERIOD = 10.hours 

    protected 

    def update_sign_in_at_periodically 
    if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago 
     session[:last_login_update_at] = Time.now 
     sign_in(current_user, :force => true) if user_signed_in? 
    end 
    end 
end 

Sin embargo, cuando intento lo anterior, usando Diseñar 3.2.4, me pongo un nuevo inicio de sesión cuando se auto-inicios de sesión de cookie (login-recuento están estableciendo 1 y current_sign_in_at). Por lo tanto, me queda solo el problema de querer que el seguimiento se actualice periódicamente, incluso para los usuarios que mantienen la sesión abierta.

class ApplicationController < ActionController::Base 
    before_filter :update_sign_in_at_periodically 
    UPDATE_LOGIN_PERIOD = 10.hours 

    protected 

    def update_sign_in_at_periodically 
    # use session cookie to avoid hammering the database 
    if !session[:last_login_update_at] or session[:last_login_update_at] < UPDATE_LOGIN_PERIOD.ago 
     session[:last_login_update_at] = Time.now 
     if user_signed_in? and current_user.current_sign_in_at < 1.minute.ago # prevents double logins 
     sign_in(current_user, :force => true) 
     end 
    end 
    end 
end 
Cuestiones relacionadas