Rails caching paginated collection

Just do some research on the best way to cache a paged item set. It is currently used by jbuilder to output JSON and plays with various cache_key options.

The best example I've seen is using the latest updated_at record plus the number of items in the collection.

def cache_key pluck("COUNT(*)", "MAX(updated_at)").flatten.map(&:to_i).join("-") end 

defined here: https://gist.github.com/aaronjensen/6062912

However, this will not work for paginated items, where I always have 10 items in my collection.

Are there any workarounds for this?

+7
caching ruby-on-rails pagination russian-doll-caching
source share
2 answers

With a paginated collection, you simply get an array. Any attempt at an array of monkey patches to include a cache key would be a bit confusing. It is best to use the cache method to generate the key in the collection for collection.

You can pass many things to the cache method to generate the key. If you always have 10 items per page, I don’t think the bill is very valuable. However, the page number and the last updated item will be.

 cache ["v1/items_list/page-#{params[:page]}", @items.maximum('updated_at')] do 

will generate a cache key, for example

 v1/items_list/page-3/20140124164356774568000 

With caching Russian dolls, you must also cache each item in the list

 # index.html.erb <%= cache ["v1/items_list/page-#{params[:page]}", @items.maximum('updated_at')] do %> <!-- v1/items_list/page-3/20140124164356774568000 --> <%= render @items %> <% end %> # _item.html.erb <%= cache ['v1', item] do %> <!-- v1/items/15-20140124164356774568000 --> <!-- render item --> <% end %> 
+9
source share

Caching page collections is difficult. The usual trick of using collection counting and max updated_at is mostly not applicable!

As you said, counting a collection is so useless if you do not allow dynamic per_page values.

The latest updated_at entirely up to you sort your collection.

Imagine adding a new entry and ending on the first page. This means that one entry, previously page 1, now enters page 2. One previous page 2 now becomes page 3. If new record 2 is not updated more recently than the previous max, the cache key remains unchanged, but the collection is not! The same thing happens when a record is deleted.

Only if you can guarantee that new entries always end on the last page and that no entries are ever deleted, using max updated_at will be a reliable way.

As a solution, you can include the total number of entries and the total number of max updated_at in the cache key in addition to the page number and per page value. This will require additional queries, but may be worth it depending on the database configuration and the number of records.

Another solution is to use a key that takes into account some reduced form of the actual contents of the collection. For example, also considering all record identifiers.

If you use postgres as a database, this stone can help you, although I have never used it myself. https://github.com/cmer/scope_cache_key

And rails 4 forks: https://github.com/joshblour/scope_cache_key

+2
source share

All Articles