Ruby on rails 如何使低级缓存与Rails中的关联缓存协作?

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

我目前正在从事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 < 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