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 product.games %>
<% 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
	 Competitor::API.find_price(id)
end

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

ActiveSupport::Cache::FileStore

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

ActiveSupport::Cache::RedisCacheStore

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
	 end
end

 # Or simply:

if stale(@product)
.. response

end

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

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