2011-04-25 17 views
4

每次我打的認證頁面,我注意到制定發出SQL語句:Rails設計:我如何(mem)緩存用戶對象的數據庫請求?

用戶負載(0.2ms的)選擇users * FROM users其中限制1

(I(usersid = 1)。 '使用Rails 3 btw ..所以cache_money似乎是一個解決方案,儘管很多搜索我沒有找到替代品)。

我在用戶模型中嘗試了許多覆蓋,只有find_by_sql似乎被調用。哪個獲得了整個SQL語句的字符串。像find_by_id或find這樣的直覺似乎並沒有被調用。我'可以'重寫此方法並收集用戶標識並從中執行合理的緩存系統 - 但這非常難看。

我也嘗試覆蓋authenticate_user,我可以攔截一個SQL嘗試,但然後調用current_user似乎再次嘗試。

簡而言之,我的用戶對象很少發生變化,而且爲了繼續使用db而不是memcache解決方案,我的用戶對象發生了變化。 (假設我願意接受使無效所有緩存的所有責任:after_save作爲該解決方案的一部分,但不是全部)

+0

設計做了很多檢查。檢查你*想要*做(通常)。但是你是對的,其中一些應該是可緩存的。你是否啓動了Ruby-Debug來找出不同的發現來自哪裏?我沒有在源代碼中看到find_by_sql。 常見的情況是正在訪問由Devise和Devise保護的頁面的登錄用戶確保用戶真正有效。如果你可以緩存這個往返行程,你應該解決很多問題。 更困難:有許多方法設計本身可以使緩存無效。例如,如果用戶重置密碼。 – 2011-04-25 19:54:53

回答

1

警告:這很可能是更好/更智能的方法。

我在幾個月前追逐了這個問題。我找到了 - 或者至少,我覺得我找到了 - 在設計加載這裏的用戶對象: https://github.com/plataformatec/devise/blob/master/lib/devise/rails/warden_compat.rb#L31

我創造了在/initializers/warden.rb該反序列化的方法猴子補丁做緩存中獲取,而不是得到。它覺得骯髒和錯誤,但它的工作。

+0

真棒亞當。可能是骯髒和錯誤的 - 但確實有效。 – user724148 2011-04-26 04:09:11

1

我一直在爲此苦苦掙扎。這樣做的

一個不太令人費解的方式是這一類方法添加到您的用戶模式:

def self.serialize_from_session(key, salt) 
    single_key = key.is_a?(Array) ? key.first : key 
    Rails.cache.fetch("user:#{single_key}") { User.find(single_key) } 
end 

請注意,我前面加上型號,以傳遞中用於存儲對象ID /檢索來自緩存的對象;你可以使用任何符合你需求的方案。

當然,唯一需要擔心的是當某些內容發生變化時,緩存中的用戶無效。如果使用會話ID作爲密鑰的一部分將用戶存儲在緩存中,但會話在模型類中不可用,並且不會由Devise傳遞給此方法。

12

以下代碼將通過其用戶ID和 緩存每個修改後的緩存失效。

class User < ActiveRecord::Base 

    after_save :invalidate_cache 
    def self.serialize_from_session(key, salt) 
    single_key = key.is_a?(Array) ? key.first : key 
    user = Rails.cache.fetch("user:#{single_key}") do 
     User.where(:id => single_key).entries.first 
    end 
    # validate user against stored salt in the session 
    return user if user && user.authenticatable_salt == salt 
    # fallback to devise default method if user is blank or invalid 
    super 
    end 

    private 
    def invalidate_cache 
     Rails.cache.delete("user:#{id}") 
    end 
end