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:
- Changing the view fragment
- Changes the Digest
- 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