1

I have an expensive .find() ActiveRecord query in Rails that I want to cache but can't:

E.g., running:

Rails.cache.fetch("beneficiary/1") { Beneficiary.find(1) }

will do nothing to cache the result. Instead it will continue to result in a database query being executed to bring in the multiple tables that a Beneficiary object needs in order for its ActiveRecord object attributes to be instantiated correctly. I want to store the result of that instantiation to prevent another database query.

My suspicion is that memcache is only saving an ActiveRecord::Relation as its return value, which is why cache hits still cause new db queries.

For ActiveRecord collections, the workaround has been to use .to_a or .all on ActiveRecord::Relation's to force memcache to save its result. But that doesn't work if the AR query is .find()

How do I cache the result of .find()?

Kelsey Hannan
  • 2,857
  • 2
  • 30
  • 46
  • Actually, what you're doing is exactly right. Your suspicion about saving an ActiveRecord::Relation object to cache instead of the record is very often the culprit for these types of problems, but it's not here. Since you're using `.find`, you're not dealing with an ActiveRecord::Relation object, but an actual model, retrieved directly from the database. `Beneficiary.find(1)` should be being cached. What does `Rails.application.config.cache_store` give? – Glyoko Mar 15 '17 at 21:02
  • 1
    Also, the question you link to is quite old. Regarding using `.to_a` or `.all` for collections: `.to_a` still works for this problem, but since Rails 4, `.all` _also_ returns an ActiveRecord::Relation object, and so won't fix this problem. – Glyoko Mar 15 '17 at 21:06
  • @Glyoko `config.action_controller.perform_caching = true` + `config.cache_store = :dalli_store, { :value_max_bytes => 99485760 }` I'm nearly certain I have memcache configured correctly because caching other .find() methods work. What is notable about this AR model when .find is called is that. even when saved to an instance variable, it results in db queries being sent to multiple models -- the instance variable itself doesn't save the result. – Kelsey Hannan Mar 15 '17 at 21:13
  • 1
    Very strange. `.find` definitely does _not_ return an AR object. You can try `Beneficiary.find(1).class.name` and `Beneficiary.all.class.name` to convince yourself of this... What are the related models that are being loaded, and is there some hook on the model (after_initialize..?) that could cause other models to be loaded. – Glyoko Mar 15 '17 at 21:16
  • Could you post the maybe add the model to your question so we can see what might cause other models to be loaded? There are a couple of things that might cause this. Off the top of my head, there's `after_initialize`, like I mentioned in the last answer, in some worlds, a `default_scope` that has an `includes` line... Would need to see the model to really figure it out. – Glyoko Mar 15 '17 at 21:21
  • That unclosed double quote tho... – Meekohi May 18 '18 at 22:25

0 Answers0