2012-01-09 10 views
8

Ho usato Devise e mi sono basato su last_sign_in_at del modello utente per funzionare se i miei clienti non sono tornati entro X giorni. Tuttavia, ho recentemente scoperto che last_sign_in_at viene aggiornato solo quando si verifica un evento di accesso al modulo vero e proprio, a differenza di quando un utente ha effettuato l'accesso automaticamente a causa dell'inclusione di memorabile.Devise: ricordabile significa che last_sign_in_at non è aggiornato da tracciabile

Se si desidera garantire che last_sign_in_at venga aggiornato ogni volta che un utente effettua l'accesso (una nuova sessione del browser), indipendentemente dal fatto che abbia utilizzato un modulo per accedere o sia stato effettuato automaticamente il login dal cookie memorizzabile, come farei per facendo questo in un modo compatibile con Devise?

risposta

5

Il gancio rintracciabile è dal gancio Warden's after_set_user - cosa si potrebbe fare per rimediare facilmente a questo è impostato un before_filter per chiamare sign_in.

Questo potrebbe essere ottimizzato, ma prova per vedere se si utilizza

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

aggiorna il timestamp last_signed_in_at.

+1

quando viene chiamato before_filter? Spero non su ogni richiesta e solo prima dell'autenticazione per la prima volta in quella sessione? Inoltre, domanda stupida, ma dove aggiungo before_filter? Ho provato ad aggiungerlo al modello utente di Devise e ho ottenuto il metodo non definito before_filter. –

+0

Questo dovrebbe essere eseguito su ogni richiesta - era solo un passo di debug rapido/sporco per vedere se ciò avrebbe risolto prima di implementare una soluzione migliore. Dovresti essere in grado di aggiungerlo a qualsiasi controller, ApplicationController se lo vuoi globale. – RobH

+3

Ciao Rob, questo è quello che ho cercato alla fine che a) controlla che un utente sia loggato prima di forzare un sign_in, e b) assicura che il metodo sign_in (forzato) venga eseguito solo una volta per sessione.(scusa il; invece delle interruzioni di riga, i commenti non consentono interruzioni di riga) 'before_filter proc {if user_signed_in? && session [: logged_signin]; sign_in (current_user,: force => true); session [: logged_signin] = true; end} ' –

13

Prendendo soluzione di Matteo, penso che il codice dovrebbe essere la seguente (si noti la non-operatore prima della seduta [: 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

Questa è la soluzione migliore? –

+0

Capito. Stai utilizzando un parametro cookie personalizzato per verificare se si tratta di una sessione nuova o esistente. Grazie per il suggerimento, questo mi sembra un approccio molto più pulito nel mio caso in quanto significa che non devo scavare negli interni di Devise. –

-1

per quanto ne so è anche possibile utilizzare update_tracked_fields! su quel modello current_user.

+0

'update_tracked_fields!' Accetta la richiesta come parametro. Dal momento che elaborare anche tracce IP. Basta fare ciò nel controller, 'current_user.update_tracked_fields! (Request)'. –

2

Devise: rememberable means that last_sign_in_at is not updated by trackable

Ampliando soluzioni precedenti, il problema con loro sarebbe che se l'utente accede normalmente, saranno "segno due volte". Che imposterà last_sign_in_at allo stesso valore (o quasi uguale) di current_sign_in_at. Sul mio sito, io uso last_sign_in_at per far sapere all'utente cosa è successo dall'ultima volta che hanno visitato il sito e, in quanto tale, ho bisogno che sia un po 'accurato. Inoltre, registra il numero di login +1.

Inoltre, ci sono persone (come me) che lasciano aperta una finestra del browser per giorni senza chiuderla (e quindi non cancellano mai il flag di sessione). Per scopi metrici, può essere utile se tale comportamento degli utenti a volte aggiorna il tempo current_sign_in_at.

Le varianti qui sotto rimederanno a queste cose.

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 

Tuttavia, quando provo quanto sopra, usando Devise 3.2.4, ottengo un nuovo account di accesso quando si auto-login per biscotto (Login-count +1 e current_sign_in_at stato impostato). Quindi, mi rimane solo il problema di volere che il monitoraggio si aggiorni periodicamente anche per gli utenti che mantengono aperta la sessione.

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 
Problemi correlati