2012-01-09 70 views
8

我正在使用Devise,並依靠用戶模型的last_sign_in_at來計算出我的客戶是否在X天內未返回。但是,最近我發現last_sign_in_at只在發生實際的表單登錄事件時更新,而不是由於包含可記住事件而自動登錄的用戶。設計:可記憶意味着last_sign_in_at沒有被跟蹤更新

如果要確保每次用戶登錄(新瀏覽器會話)時都更新last_sign_in_at,無論他們是使用表單登錄還是由可記憶的cookie自動登錄,我該如何去解決以設計兼容的方式做到這一點?

回答

5

可跟蹤掛鉤來自Warden's after_set_user掛鉤 - 您可以通過設置before_filter來調用sign_in

這可以優化,但測試以查看是否使用

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

更新last_signed_in_at時間戳。

+1

何時調用before_filter?我希望不是每次請求時,並且只在第一次會話之前進行身份驗證?此外,愚蠢的問題,但我在哪裏添加before_filter?我嘗試將它添加到Devise用戶模型,並得到了未定義的方法before_filter。 – 2012-01-09 23:49:02

+0

這將在每個請求上運行 - 這只是一個快速/骯髒的調試步驟,看看在實施更好的解決方案之前是否可以解決問題。如果你希望它是全局的,你應該可以將它添加到任何控制器,ApplicationController中。 – RobH 2012-01-10 00:23:34

+3

嗨,羅布,這是我最終去哪a)在強制sign_in之前檢查用戶登錄,並且b)確保sign_in(強制)方法僅在每個會話中執行一次。(原諒;而不是換行符,註釋不允許換行)'before_filter proc {if user_signed_in? && session [:logged_signin]; sign_in(current_user,:force => true); session [:logged_signin] = true; end}' – 2012-01-10 08:34:36

13

以馬修的解決方案,我認爲該代碼應爲以下(注意之前的會議上沒有運營商[: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

這是最好的解決方案了嗎? – 2014-09-03 14:25:12

+0

明白了。您正在使用自定義Cookie參數來檢查這是新的還是現有的會話。感謝提示,這對我來說就像是一個更清潔的方法,因爲這意味着我不必深入Devise的內部。 – 2015-02-11 16:48:54

-1

據我所知,你還可以對current_user模型中使用update_tracked_fields!

+0

'update_tracked_fields!'將請求作爲參數。由於設計也跟蹤IP。只需在控制器中執行此操作,即'current_user.update_tracked_fields!(request)'。 – 2015-12-14 08:26:42

2

Devise: rememberable means that last_sign_in_at is not updated by trackable

擴展在以前的解決方案,與他們的問題是,如果在正常的用戶登錄,他們將「登錄兩次。」這會將last_sign_in_at設置爲與current_sign_in_at相同(或幾乎相同)的值。 在我的網站上,我使用last_sign_in_at讓用戶知道自他們上次訪問該網站以來發生了什麼,因此我需要它有些準確。此外,它還記錄+1登錄計數。

此外,還有一些人(比如我自己)讓瀏覽器窗口打開幾天而不關閉它(因此永遠不會清除會話標誌)。出於度量目的等,如果這樣的用戶行爲有時會刷新時間,那麼它可能很有用。

以下變體將補救這些事情。

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 

然而,當我嘗試上面,利用設計3.2.4,我得到一個新的登錄時自動登錄由餅乾(登錄數+1和current_sign_in_at被設置)。所以,我只剩下希望跟蹤定期更新的問題,即使對於保持會話打開的用戶也是如此。

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 
相關問題