Ruby on rails 如何使低级缓存与Rails中的关联缓存协作?
我目前正在从事Rails 5的一个项目。我想提高性能,所以我决定使用低级别缓存,如下所示:Ruby on rails 如何使低级缓存与Rails中的关联缓存协作?,ruby-on-rails,activerecord,Ruby On Rails,Activerecord,我目前正在从事Rails 5的一个项目。我想提高性能,所以我决定使用低级别缓存,如下所示: class User < ApplicationRecord has_one :profile def cached_profile Rails.cache.fetch(['Users', id, 'profile', updated_at.to_i]) do profile end end end class Profile < Applicat
class User < ApplicationRecord
has_one :profile
def cached_profile
Rails.cache.fetch(['Users', id, 'profile', updated_at.to_i]) do
profile
end
end
end
class Profile < ApplicationRecord
belongs_to :user, touch: true
end
u.profile
不应从数据库中获取,因为它已经从redis中检索到,如何实现这一点
更新1:
我发现在ActiveRecord::Base
的实例中有一个实例变量@association\u cache
,它存储缓存的关联并确定是否应从数据库中检索关联
我想我可以做一些类似于
user.instance\u variable\u get(:@association\u cache)['profile']=cached\u profile
的事情来让它工作。但是@association\u缓存中的值是ActiveRecord::Associations::HasOneAssociation
的一个实例,我不知道当前如何为其构建用户。您可以直接覆盖profile
方法来应用低级别缓存
class User
has_one :profile
def profile
Rails.cache.fetch(['Users', id, 'profile', updated_at.to_i]) do
super
end
end
end
class Profile
belongs_to :user, touch: true
end
但是要小心,因为你可能会遇到一些惊喜。例如,您还应该在profile=
setter上读取缓存。ActiveRecord::Base的实例中有一个实例变量@association\u cache,它存储缓存的关联,并确定是否应从数据库检索关联
我们可以通过@association\u cache
实现它,如:
class User < ApplicationRecord
has_one :profile
def cached_profile
cache = Rails.cache.fetch(['Users', id, 'profile', updated_at.to_i]) do
profile
end
reflection = self.class.reflect_on_association(:profile)
if association_instance_get(name).nil?
association = reflection.association_class.new(self, reflection)
association.target = cache
association_instance_set(:profile, association)
end
cache
end
end
class Profile < ApplicationRecord
belongs_to :user, touch: true
end
更新:
我为此做了一块宝石
class User < ApplicationRecord
include CacheAssociations
has_one :profile
cache_association :profile
end
class用户
它也在做同样的事情,但是它很简洁,而且使用起来也很简单。我想知道为什么在缓存的\u profile
中调用“super”会起作用,是不是应该改为”profile
?@XavierDelamotte抱歉,这是个打字错误。我更正了。既然rails已经自动缓存了profile
,为什么需要引入缓存的_配置文件?请参阅->CachingI我认为@association\u cache
是我应该走的正确道路。
irb> u = User.take
irb> u.cached_profile # fetch the profile from the database and use the redis to cache it
Profile Load (1.4ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
irb> u.profile # use the cached version from the redis
irb> u.profile.reload # reload from the database
Profile Load (1.4ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
class User < ApplicationRecord
include CacheAssociations
has_one :profile
cache_association :profile
end