User Cache and Rails Associations - Overwriting ActiveRecord.find

I want to write my own ActiveRecord cache, only for find_by_id right now. To do this, I want to rewrite the find method when only one int is given, use my cache, otherwise use the default implementation.

 class X < ActiveRecord::Base def self.find(*args) return XCache[args[0]] if args.size == 1 && args[0].is_a?(Numeric) return super.find(*args) end end 

Everything works, except for the case of communication that I have with other X instances, for example. parent-child relationship:

 has_many :x_children has_many :children, :class_name => "X", :through => :x_children 

When I call X.find(1).children , I get an Enumerator instead of Array , which is bad, because sometimes I use the [] operator.

Even using an enumerator does not work well - when I repeat the last record, I get:

 NoMethodError: undefined method `call' for :all:Symbol 

Any help would be greatly appreciated

Further explanation:

XCache is just a class that caches ActiveRecord instances. The simplest implementation could be

 class XCache @@cache = {} def self.[id] return @@cache[id] ||= X.find(id) end end 

(A more complex implementation may include expiration time, Memcached, etc., and a more general solution may support several classes of models).

I don’t think my problem is with cache implementation (but I could be wrong)

+4
source share
2 answers

As you saw, there is a lot of hidden complexity. You could look into the cache-money gem, these guys spent a lot of energy figuring this out.

Other gems to watch: simple_cacheable

+1
source

Not sure if this helps, but ... This is what the find looks inside:

  def find(*args) options = args.extract_options! validate_find_options(options) set_readonly_option!(options) case args.first when :first then find_initial(options) when :last then find_last(options) when :all then find_every(options) else find_from_ids(args, options) end end 

You do not need to overload "find", but "find_from_ids"

This will allow you to leave all the other search methods that are used alone and just aim for your own use. Given that enumerations are what find (: all) returns ... this may help your situation (or maybe not).

Is it possible that Xcache returns only one ActiveRecord, or is it possible that it sometimes returns a set ... or even an empty set?

Perhaps you can try the options:

 def self.find(*args) if args.size == 1 && args[0].is_a?(Numeric) rval = XCache[args[0]] return rval if rval.present? end super.find(*args) end 
0
source

All Articles