At a recent meetup I was explaining the benefits of caching model objects and how it can help performance by reducing calls to your database. I was only able to give contrived examples at the time but I thought that since I recently had a use case that fell into this neighborhood I thought I’d share. I’ll note that Rails will, by default, write to the file system but for optimal performance you’ll want to use a memory based store like memcached or redis.
If you open up a Rails console and access information from your database you can see the time it spends looking up that information. For example:
I picked an article number and did a query of its title and see that it was a 0.5 and 0.4ms call on the database. The database I am working with locally is quite small and the query isn’t very complex. Regardless, with caching we can remove database calls from the equation. Caching works like a hash with a key and a value. The syntax is
Rails.cache.write('key', value) and then
With the read action there is no database call. Caching also supports expiring the cache, versioning it, giving it a time to live and so on. More infomation can be found in the Rails guides.
Aside from reading and writing, you can also perform a fetch which will read the result that is stored in the cache and if there is nothing there it will create the cache by performing the passed in block.
We see that the first time we attempted to fetch the
ArticleTitle it didn’t exist so it made a database query but on each subsequent fetch there was no database call.
The use case that occurred recently was that our site at work has become a target for hackers. We’re using the fantastic rack attack gem that I created a cron job to poll daily and update the list by removing ip addresses that are no longer on the list and adding any new ones to the list. I created a
Blacklist table in the database with the following cache actions:
So I am creating a
blacklisted_ips that doesn’t expire unless the
after_commit gets called by the blacklist table being changed. If the table is changed, I delete the cache so the most recent list of ips is in the cache. For reference, here is my rack attack initializer
I know, pretty basic eh?