I am currently working on a project with Rails 5. I want to boost the performance, so I decided to use Low-Level caching like the following:
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
It works fine respectively. But now I want to make the two caches to collaborate. What I want is that the associated object doesn't need to be retrieved from the database once it is retrieved from the cache store(redis here).
irb> u = User.take
irb> u.cached_profile # fetch from the redis. Can I set the association caching in `cached_profile`?
irb> u.profile # fetch from the database
Profile Load (1.4ms) SELECT "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
irb> u.profile # fetch from the association caching
u.profile shouldn't fetch from the database because of it's already retrived from the redis, how to achieve this?
Update 1:
I found that there's an instance variable @association_cache in the instance of ActiveRecord::Base, which stores cached associations and determines if an association should be retrieved from the database.
I think I could do something like user.instance_variable_get(:@association_cache)['profile'] = cached_profile to make it work. But the value in the @association_cache is an instance of ActiveRecord::Associations::HasOneAssociation and I don't know how to build the user to it currently.