16 MarRails associations and interlock finders

Tuesday, 16 March 2010 — 08:45

If you are using Interlock from Evan Weaver in your Rails project, this post might be of your interest. As you can see from the code, Interlock caches all those requests using find, find_by, find_all_by_id. From Evan Readme notes:

Now, whenever you call find, find_by_id, or find_all_by_id with a single id or an array of ids, the
cache will be used. The cache key for each record invalidates when the record is saved or destroyed. Memcached’s multiget mode is used for maximum performance.

If you pass any parameters other than ids, or use dynamic finders, the cache will not be used. This means that
:include works as expected and does not require complicated invalidation

I was fighting recently with a memcache problem on a project that used a customized version of interlock. Because of this customized version, developer had to manually reload memcache after saving/updating a new record. As you can imagine, this code is error prone, as well as very easy the developer can forget about reloading in some cases. Indeed, that’s what happened on this case.

Let’s define de scenario:

#project.rb
has_one :manager, :foreign_key => "project_id", :dependent => :destroy

#manager.rb
belongs_to :assistant, :dependent => :destroy

Now, let’s roll up our sleeves and open a ruby console. I added some loggers in order you can see what’s going on:

project = Project.find(:last)
project.manager
project.manager.assistant
project.manager
project.manager.assistant
Mar 16 09:40:12 dhcp-client-0-104 rails[4870]: Project Load (0.000635)   SELECT * FROM `projects` ORDER BY projects.id DESC LIMIT 1
Mar 16 09:40:40 dhcp-client-0-104 rails[4870]: Manager Load (0.000579)   SELECT * FROM `managers` WHERE (`managers`.project_id = 18320478) LIMIT 1
Mar 16 09:41:34 dhcp-client-0-104 rails[4870]: [interlock] model interlock::Assistant:find:117255:default is loading from memcached

The important lines are the last two at the end. No matter how many times you ask for the manager or the assistant, in both cases same thing will happen. In the case of the manager, it will always go through database. The reason is that we are making the query by project_id and not by id. As you read at the beginning of the post, finders in interlock are just activated when you find by id. Otherwise, it goes directly through database.

In our example, project.manager.assistant goes through memcache though. Why?. Simple. In this case we are executing a find_by_id. We need to look at Assistants table for the record with id=x.

Basically depending on how you build your associations, some calls will go through memcache, and some others, directly through database.

Ger