ActiveResource makes talking to REST API’s easy. The beauty of ActiveResource objects is that they mimic ActiveRecord objects, providing a familiar interface to rails developers.
The problem is that a REST API is not a database connection. There’s quite a bit going on to create your objects. ActiveResource sends an API request, your API handles that, gets the records from the database, marshals it into json, sends it over the network, ActiveResource un-marshals the data, and finally returns a ruby object.
If you have a page with many ActiveResource objects being displayed on it, you can kiss any hopes of scalability and performance goodbye.
So it makes sense that you would try and limit the number of times you request the same information from an API. Ideally you would take advantage of cache-control max-age headers, last-modified headers and ETags to limit the number of redundant API requests. ActiveResource doesn’t respect any of these caching strategies, and adding support for them turns out to be a non-trivial task. Believe me, I tried.
Thankfully there is a simple solution, implement a read through cache.
What is a Read Through Cache?
A read through cache is quite simple, it’s designed to serve data from a cache if it has it, otherwise to fetch it from the source.
The algorithm is as follows:
- Attempt to read from the cache.
- If no results are found, read from the original source.
- Write the results to the cache.
- Return the results.
An Implementation
In order to add read through caching to ActiveResource, we need to build a module that can hook into the ActiveResource find class methods:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
If you include this module in any ActiveResource class and call the find method you will see that find_with_read_through_cache is called and prints a message letting you know about it.
In order to cache an object, we need a suitable cache key, something unique that we can use to store and retrieve the objects. A combination of the ActiveResource class name and the arguments passed to find should do just nicely:
1 2 3 | |
Using Rails.cache we can implement the basic read through cache algorithm quite easily. The only quirk is that we must call dup on anything pulled from Rails.cache that we intend to modify it later:
1 2 3 4 5 6 7 8 9 10 11 | |
If you are familiar with how Rails.cache works, then you will have noticed the flaw in the above code.
The cache will be held onto for ever.
Probably not what you want as the results could change and you have no way to flush the cache.
So we need a way to set the cache expiry.
A class level cache_for attribute, and a cache_expires_in method to retrieve the value or a default if none is provided.
Then we can pass the :expires_in parameter to Rails.cache.write and our simple caching strategy is complete:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
With this simple module we can now cache ActiveResource objects for as long as we’re comfortable.
I used this technique on a recent project, combined with a cron job to keep the caches warm, to ensure that pages including upwards of 30 ActiveResource objects were able to load with 100ms response times.

