我有一张languages
表,几乎没有任何变化。我试图避免在这个表上进行初始缓存的数据库查询。
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
方法添加到所有这些模型中会非常混乱。
答案 0 :(得分:1)
要在单个请求期间缓存查询,除了确保使用ActiveRecord::QueryCache
中间件之外,您不必执行任何操作。如果你打两次电话:
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
您可以将模块mixin设置为根据需要使用尽可能多的模型。它确实意味着您必须编写自己的关联查找。您也可以使用回调来执行此操作:
after_commit do
Rails.cache.write(cache_key, self, expires_in: self.class.cache_period)
end