2013-09-23 54 views
1

我有一個languages表,幾乎每個變化。我試圖避免在這個表上的數據庫查詢其他初始緩存。強制ActiveRelation使用rails緩存

class Language < ActiveRecord::Base 
    attr_accessible :code, :name, :native_name 

    def self.find_by_name_in_cache(name) 
    get_all_cached.find {|l| l.name == name} 
    end 

    def self.find_by_code_in_cache(code) 
    get_all_cached.find {|l| l.code == code} 
    end 

    def self.find_by_id_in_cache(id) 
    get_all_cached.find {|l| l.id == id} 
    end 

    def self.get_all_cached 
    Rails.cache.fetch('all_languages') {Language.all} 
    end 
end 

所有隻要去罰款,我使用的,我已經定義了find_in_cache方法之一。

我的問題是,我如何強制ActiveRelation也使用緩存。

例如,請考慮以下用戶模型:

class User < ActiveRecord::Base 
    belongs_to :native_language, :class_name => :Language, :foreign_key => :native_language_id 
end 

當我訪問@user.native_language,它查詢language從數據庫中。我會高度讚賞任何想法,以防止這種情況。

我知道我能做到以下幾點:

class User < ActiveRecord::Base 
    belongs_to :native_language, :class_name => :Language, :foreign_key => :native_language_id 

    def native_language_cached 
    Language.find_by_id_in_cache(self.native_language_id) 
    end 
end 

但是,我希望的是更透明的解決方案,我的很多表的參考languages表,這將是如此凌亂的cached方法添加到所有這些模型。

+1

看看這寶石有助於https://github.com/Shopify/identity_cache – AJcodez

+0

@AJcodez,對於創業板,它的一個不錯的寶石感謝。它基本上是我添加的'find_in_cache'和'cached'方法的一個通用實現,因此它使我無需在每個模型中重複這些方法。但是,它與我的解決方案一樣具有侵入性。我必須使用'cache'方法而不是默認的活動記錄方法。 –

+0

我的意思是你必須使用不同的方法,但你不希望默認的活動記錄功能,所以你可能不能使用默認的活動記錄moethds – AJcodez

回答

1

要在單個請求期間緩存查詢,除了確保使用中間件之外,您不必執行任何操作。如果你把它叫做兩次:

2.times{ user.native_language.to_s } 

你會看到你的日誌是這樣的:跨請求

Language Load (0.2ms) SELECT `languages`.* FROM `languages` WHERE ... 
CACHE (0.0ms) SELECT `languages`.* FROM `languages` WHERE ... 

緩存需要手動緩存。 identity_cache gem可能對你正在嘗試做的事情(緩存關聯)很有用。

最快的方法可能只是將expires_in選項添加到您的代碼中。你可以寫一個通用cached_find方法如下所示:

def self.cached_find(id) 
    key = model_name.cache_key + '/' + id 
    Rails.cache.fetch(key) do 
    find(id).tap do |model| 
     Rails.cache.write(key, model, expires_in: cache_period) 
    end 
    end 
end 

def self.cache_period 
    3.days 
end 

你可以把它的模塊混入儘可能多的車型使用是必要的。這意味着你必須編寫自己的關聯查找。您也可以回調做:

after_commit do 
    Rails.cache.write(cache_key, self, expires_in: self.class.cache_period) 
end