Robert's Homepage

Caching Concepts In Rails

#development #ruby-on-rails #software-engineering

Basics Reference

Caching is only enabled in production environment (by default)

Page: Requests done through web sever vs Rails Stack

Action: Similar to Page, but hits Rails stack to execute before_filter and similar authentication means.

Fragment: Different parts of the page have different caching characteristics - view logic can be wrapped in cache blocks. Known as key-base-expiration.

<% cache  product do %>
<% end  %>

# Rails writes cache entry to `views/products/product_id/updated_at`

The string of characters at the end of the key is a template tree digest —it’s a hash digest of view fragment being cache:

  1. Changing the view fragment
  2. Changes the Digest
  3. Expires the file

You can also cache templates in the render function by using the cached: true property. Known as collection caching.

ActiveRecord generates keys based on the name and record id.

Russian Doll Caching: cached fragments nested in other cached fragments.

<% cache  product do %>
   <%= render %>
<% end  %>

<% cache game do %>
   <%= render game %>
<% end %>

if a single product is updated, all the other inner fragments can be reused when regenerating the outer fragment.

Important to add (touch:_ true) attributes to ApplicationRecords (models) so that the updated_at attribute is changed properly and avoids serving stale data

Low Level Caching: for caching values that are not view fragments. The first argument fetches the result. If cache miss, Rails executes the block passed to it

Rails.cache.fetch("#{cache_key}/competing_price", expires_in: 12.hours) do

SQL Caching: Rails automatically caches SQL queries, so the second SQL query won’t hit the database.

Cache Stores: ActiveSupport::Cache::Store

config.cache_store = :memory_store, { size: 64.megabytes }

Methods: read, write delete, exist?, fetch


config.cache_store = :file_store, "/path/to/cache/directory"

Allows for shareable cache between multiple server processes. ActiveSupport::Cache::MemCacheStore:

Uses bundled memcache gem, for a single, shared cache cluster with very high performance and redundancy.

You need to specify the address of your memchaced servers in your cluster


Rails can also use Redis cache.

Conditional GETS

Using the “HTTP_IF_NONE_MATCH” headers in a request we can send cached content back if the content identifier (tag) is different from that on the server

Can do this easily with:

if stale?(last_modified: @product.updated_at.utc, etag: @product.cache_key)
	 respond_to do |wants|
		# ... normal response processing

 # Or simply:

if stale(@product)
.. response


For default rendering (i.e. not calling render yourself):

fresh_when last_modified: @product.published_at.utc, etag: @product