We're not actually using cached_model for Jamglue, but since I took the time to figure it out, I thought I'd post on how to make the Robot Coop's cached_model work with Single Table Inheritance.
I like the idea of cached_model- make your models inherit from CachedModel instead of ActiveRecord::Base, and get automatic transparent speed-ups.
But there are two problems that arise if you also use single table inheritance though. To illustrate them, I'll go with the old example of a Shape class, with Circle and Square children.
So we go from class Shape < ActiveRecord::Base, with Circle < Shape and Square < Shape, to having Shape < CachedModel and the other two unchanged.
The first problem is that while Circle.find(3) and Square.find(5) keep working, the more general Shape.find(3) no longer returns anything. A glance at the log shows that the SQL query now includes the requirement that type = 'Shape', which of course never happens (type is always Circle or Square).
This happens because anytime a class isn't an immediate subclass of ActiveRecord::Base, single table inheritance adds the type condition. The fastest way to fix this is to override descends_from_active_record? on the parent class, Shape:
def self.descends_from_active_record?
# hide the existance of CachedModel so that find won't add a type condition
return name == "Shape"
end
The second problem is with the caching. CachedModel uses keys of the form Class:id, but if you watch memcached's logs, you'll see that both Circle:3 and Shape:3 end up being set and get, which is inefficient and also means you're probably only expiring one whenever the data changes.
To fix this, we override cache_key_local, again in the parent class, Shape. We force it to always use Shape in the key, unifying the keys in the cache:
def cache_key_local
# always use Shape, never Circle or Square
return "Shape:#{id}"
end
Both of these fixes are kind of hacky, but they may help somebody else
trying to quickly combine cached_model with single table
inheritance. Also, I thought anybody writing their own model caching
system might be interested to see the shortcomings with the current
implementation of cached_model for future reference.
previous entry: