1 Basic Caching
Esta es una introducción a tres tipos de técnicas de almacenamiento en caché: página, acción y
almacenamiento en caché de fragmentos. De forma predeterminada, Rails proporciona almacenamiento en caché de fragmentos. Para usar
caché de páginas y acciones, deberá agregar actionpack-page_caching
y
actionpack-action_caching
a suGemfile
.
De forma predeterminada, el almacenamiento en caché solo está habilitado en su entorno de producción. Jugar
con el almacenamiento en caché local, querrá habilitar el almacenamiento en caché en su
entorno estableciendo config.action_controller.perform_caching
en true
en
el archivo config/environment/*.rb
relevante:
config.action_controller.perform_caching = true
Cambiar el valor de config.action_controller.perform_caching
solo tienen un efecto en el almacenamiento en caché proporcionado por el componente Action Controller.
Por ejemplo, no afectará el almacenamiento en caché de bajo nivel, que abordamos
abajo.
1.1 Page Caching
El almacenamiento en caché de páginas es un mecanismo de Rails que permite la solicitud de una página generada para ser cumplido por el servidor web (es decir, Apache o NGINX) sin tener que ir a través de toda la pila de Rails. Si bien esto es súper rápido, no se puede aplicar a cada situación (como páginas que necesitan autenticación). Además, porque el El servidor web está sirviendo un archivo directamente desde el sistema de archivos que necesitará implementar la caducidad de la caché.
El almacenamiento en caché de páginas se ha eliminado de Rails 4. Consulte la actionpack-page_caching gem.
1.2 Action Caching
El almacenamiento en caché de página no se puede utilizar para acciones que tienen filtros anteriores, por ejemplo, páginas que requieren autenticación. Aquí es donde entra en juego el almacenamiento en caché de acciones. El almacenamiento en caché de acciones funciona como el almacenamiento en caché de páginas, excepto que la solicitud web entrante llega a la pila de Rails para que antes de que se puedan ejecutar los filtros antes de que se sirva la caché. Esto permite que la autenticación y otras restricciones se ejecuten sin dejar de ofrecer el resultado de la salida de una copia en caché.
Action Caching se ha eliminado de Rails 4. Consulte la actionpack-action_caching gem. Consulte la DHH's key-based cache expiration overview para el método recientemente preferido.
1.3 Fragment Caching
Las aplicaciones web dinámicas suelen crear páginas con una variedad de componentes que no todos los cuales tienen las mismas características de almacenamiento en caché. Cuando diferentes partes del La página debe almacenarse en caché y caducar por separado, puede usar el almacenamiento en caché de fragmentos.
El almacenamiento en caché de fragmentos permite que un fragmento de la lógica de vista se envuelva en un bloque de caché y se sirva fuera del almacén de caché cuando llegue la siguiente solicitud.
Por ejemplo, si desea almacenar en caché cada producto en una página, puede usar este código:
<% @products.each do |product| %>
<% cache product do %>
<%= render product %>
<% end %>
<% end %>
Cuando su aplicación reciba su primera solicitud a esta página, Rails escribirá una nueva entrada de caché con una clave única. Una clave se parece a esto:
views/products/index:bea67108094918eeba42cd4a6e786901/products/1
La cadena de caracteres en el medio es un resumen de árbol de plantilla. Es un hash resumen calculado en función del contenido del fragmento de vista que está almacenando en caché. Si cambia el fragmento de vista (por ejemplo, el HTML cambia), el resumen cambiará, caducando el archivo existente.
Una versión de caché, derivada del registro del producto, se almacena en la entrada de caché. Cuando se toca el producto, la versión de la caché cambia y los fragmentos almacenados que contienen la versión anterior se ignoran.
las tiendas de caché como Memcached eliminarán automáticamente los archivos de caché antiguos.
Si desea almacenar en caché un fragmento en determinadas condiciones, puede utilizar
cache_if
o cache_unless
:
<% cache_if admin?, product do %>
<%= render product %>
<% end %>
1.3.1 Collection caching
El ayudante render
también puede almacenar en caché plantillas individuales renderizadas para una colección.
Incluso puede mejorar el ejemplo anterior con each
leyendo todo el caché
plantillas a la vez en lugar de una por una. Esto se hace pasando cached: true
al renderizar la colección:
<%= render partial: 'products/product', collection: @products, cached: true %>
Todas las plantillas almacenadas en caché de renderizaciones anteriores se recuperarán a la vez con mucho mayor velocidad. Además, las plantillas que aún no se hayan almacenado en caché serán escrito en la caché y recuperado en el siguiente render.
1.4 Russian Doll Caching
Es posible que desee anidar fragmentos almacenados en caché dentro de otros fragmentos almacenados en caché. Esto es llamado caché de muñecas rusas.
La ventaja del almacenamiento en caché de muñecas rusas es que si se actualiza un solo producto, todos los demás fragmentos internos se pueden reutilizar al regenerar el exterior fragmento.
Como se explicó en la sección anterior, un archivo en caché caducará si el valor de
updated_at
cambia para un registro del que depende directamente el archivo en caché.
Sin embargo, esto no caducará ningún caché en el que esté anidado el fragmento.
Por ejemplo, adopte la siguiente perspectiva:
<% cache product do %>
<%= render product.games %>
<% end %>
Lo que a su vez muestra esta vista:
<% cache game do %>
<%= render game %>
<% end %>
Si se cambia cualquier atributo del juego, el valor de updated_at
se establecerá en el
tiempo actual, con lo que expira el caché. Sin embargo, debido a que updated_at
no se cambiará para el objeto del producto, esa caché no caducará y
su aplicación servirá datos obsoletos. Para solucionar este problema, vinculamos los modelos con
el método touch
:
class Product < ApplicationRecord
has_many :games
end
class Game < ApplicationRecord
belongs_to :product, touch: true
end
Con touch
establecido entrue
, cualquier acción que cambie updated_at
para un juego
registro también lo cambiará para el producto asociado, con lo que expirará el
cache.
1.5 Shared Partial Caching
Es posible compartir parciales y el almacenamiento en caché asociado entre archivos con diferentes tipos de mime. Por ejemplo, el almacenamiento en caché parcial compartido permite a los escritores de plantillas compartir un parcial entre archivos HTML y JavaScript. Cuando las plantillas se recopilan en las rutas del archivo de resolución de plantillas, solo incluyen la extensión del idioma de la plantilla y no el tipo mime. Debido a esto, las plantillas se pueden usar para múltiples tipos de mímica. Tanto las solicitudes HTML como JavaScript responderán al siguiente código:
render(partial: 'hotels/hotel', collection: @hotels, cached: true)
Cargará un archivo llamado hotels/hotel.erb
.
Otra opción es incluir el nombre de archivo completo del parcial a renderizar.
render(partial: 'hotels/hotel.html.erb', collection: @hotels, cached: true)
Cargará un archivo llamado hotels/hotel.html.erb
en cualquier tipo de archivo mime, por ejemplo, podría incluir este parcial en un archivo JavaScript.
1.6 Managing dependencies
Para invalidar correctamente la caché, debe definir correctamente la almacenamiento en caché de dependencias. Rails es lo suficientemente inteligente como para manejar casos comunes para que usted no tengo que especificar algo. Sin embargo, a veces, cuando se trata de helpers, por ejemplo, debe definirlos explícitamente.
1.6.1 Implicit dependencies
La mayoría de las dependencias de la plantilla se pueden derivar de llamadas a render
en la plantilla
sí mismo. A continuación se muestran algunos ejemplos de llamadas de renderización que ActionView::Digestor
conoce
cómo decodificar:
render partial: "comments/comment", collection: commentable.comments
render "comments/comments"
render 'comments/comments'
render('comments/comments')
render "header" translates to render("comments/header")
render(@topic) translates to render("topics/topic")
render(topics) translates to render("topics/topic")
render(message.topics) translates to render("topics/topic")
Por otro lado, algunas llamadas deben cambiarse para que el almacenamiento en caché funcione correctamente. Por ejemplo, si está pasando una colección personalizada, deberá cambiar:
render @project.documents.where(published: true)
a:
render partial: "documents/document", collection: @project.documents.where(published: true)
1.6.2 Explicit dependencies
A veces tendrá dependencias de plantilla que no se pueden derivar en absoluto. Esta Suele ser el caso cuando la renderización ocurre en ayudantes. He aquí un ejemplo:
<%= render_sortable_todolists @project.todolists %>
Deberá usar un formato de comentario especial para llamarlos:
<%# Template Dependency: todolists/todolist %>
<%= render_sortable_todolists @project.todolists %>
En algunos casos, como una configuración de herencia de una sola tabla, es posible que tenga un montón de dependencias explícitas. En lugar de escribir todas las plantillas, puede utilizar un comodín para que coincida con cualquier plantilla en un directorio:
<%# Template Dependency: events/* %>
<%= render_categorizable_events @person.events %>
En cuanto al almacenamiento en caché de la colección, si la plantilla parcial no comienza con una limpieza llamada de caché, aún puede beneficiarse del almacenamiento en caché de la colección agregando un formato de comentario en cualquier lugar de la plantilla, como:
<%# Template Collection: notification %>
<% my_helper_that_calls_cache(some_arg, notification) do %>
<%= notification.name %>
<% end %>
1.6.3 External dependencies
Si usa un método auxiliar, por ejemplo, dentro de un bloque en caché y luego actualiza ese ayudante, tendrás que aumentar el caché también. Realmente no importa como lo hace, pero el MD5 del archivo de plantilla debe cambiar. Una recomendación es simplemente sea explícito en un comentario, como:
<%# Helper Dependency Updated: Jul 28, 2015 at 7pm %>
<%= some_helper_method(person) %>
1.7 Low-Level Caching
A veces es necesario almacenar en caché un valor particular o el resultado de una consulta en lugar de almacenar en caché fragmentos de vista. El mecanismo de almacenamiento en caché de Rails funciona muy bien para almacenar cualquier tipo de información.
La forma más eficiente de implementar el almacenamiento en caché de bajo nivel es utilizando el método Rails.cache.fetch
. Este método lee y escribe en la caché. Cuando se pasa un solo argumento, se obtiene la clave y se devuelve el valor de la caché. Si se pasa un bloque, ese bloque se ejecutará en caso de que falle la caché. El valor de retorno del bloque se escribirá en la caché bajo la clave de caché dada, y se devolverá ese valor de retorno. En caso de acierto en la caché, el valor almacenado en caché se devolverá sin ejecutar el bloque.
Considere el siguiente ejemplo. Una aplicación tiene un modelo de "Producto" con un método de instancia que busca el precio del producto en un sitio web de la competencia. Los datos devueltos por este método serían perfectos para el almacenamiento en caché de bajo nivel:
class Product < ApplicationRecord
def competing_price
Rails.cache.fetch("#{cache_key_with_version}/competing_price", expires_in: 12.hours) do
Competitor::API.find_price(id)
end
end
end
Observe que en este ejemplo usamos el método cache_key_with_version
, por lo que la clave de caché resultante será algo como products/233-20140225082222765838000/competing_price
. cache_key_with_version
genera una cadena basada en el nombre de clase del modelo,id
y atributos updated_at
. Esta es una convención común y tiene la ventaja de invalidar la caché cada vez que se actualiza el producto. En general, cuando utiliza el almacenamiento en caché de bajo nivel para la información de nivel de instancia, debe generar una clave de caché.
1.8 SQL Caching
El almacenamiento en caché de consultas es una función de Rails que almacena en caché el conjunto de resultados devuelto por cada consulta. Si Rails vuelve a encontrar la misma consulta para esa solicitud, utilizará el conjunto de resultados en caché en lugar de ejecutar la consulta en la base de datos de nuevo.
Por ejemplo:
class ProductsController < ApplicationController
def index
# Run a find query
@products = Product.all
...
# Run the same query again
@products = Product.all
end
end
La segunda vez que se ejecuta la misma consulta en la base de datos, en realidad no llegará a la base de datos. La primera vez que se devuelve el resultado de la consulta, se almacena en la caché de consultas (en la memoria) y la segunda vez se extrae de la memoria.
Sin embargo, es importante tener en cuenta que los cachés de consultas se crean al comienzo de una acción y destruida al final de esa acción y, por lo tanto, persisten solo durante el duración de la acción. Si desea almacenar los resultados de la consulta en un formato más de manera persistente, puede hacerlo con almacenamiento en caché de bajo nivel.
2 Cache Stores
Rails proporciona diferentes almacenes para los datos almacenados en caché (además de SQL y page almacenamiento en caché).
2.1 Configuration
Puede configurar el almacén de caché predeterminado de su aplicación configurando el
Opción de configuración config.cache_store
. Otros parámetros se pueden pasar como
argumentos para el constructor de la tienda de caché:
config.cache_store = :memory_store, { size: 64.megabytes }
Alternativamente, puede llamar a ActionController::Base.cache_store
fuera de un bloque de configuración.
Puede acceder a la caché llamando a Rails.cache
.
2.2 ActiveSupport::Cache::Store
Esta clase proporciona la base para interactuar con la caché en Rails. Esta es una clase abstracta y no puede usarla por sí sola. En su lugar, debe utilizar una implementación concreta de la clase vinculada a un motor de almacenamiento. Rails se envía con varias implementaciones documentadas a continuación.
Los métodos principales para llamar son read
, write
, delete
, exist?
, y fetch
. El método de búsqueda toma un bloque y devolverá un valor existente de la caché o evaluará el bloque y escribirá el resultado en la caché si no existe ningún valor.
Hay algunas opciones comunes que pueden ser utilizadas por todas las implementaciones de caché. Estos se pueden pasar al constructor oa los diversos métodos para interactuar con las entradas.
:namespace
: esta opción se puede usar para crear un espacio de nombres dentro del almacén de caché. Es especialmente útil si su aplicación comparte un caché con otras aplicaciones.:compress
: habilitado de forma predeterminada. Comprime las entradas de caché para que se puedan almacenar más datos en el mismo espacio de memoria, lo que genera menos desalojos de caché y mayores tasas de aciertos.:compress_threshold
: el valor predeterminado es 1kB. Las entradas de caché mayores que este umbral, especificadas en bytes, se comprimen.:expires_in
- Esta opción establece un tiempo de vencimiento en segundos para la entrada de la caché, si el almacén de caché lo admite, cuando se eliminará automáticamente de la caché.:race_condition_ttl
: esta opción se utiliza junto con la opción:expires_in
. Evitará las condiciones de carrera cuando las entradas de la caché caduquen al evitar que múltiples procesos regeneren simultáneamente la misma entrada (también conocido como efecto de pila de perros). Esta opción establece el número de segundos que se puede reutilizar una entrada vencida mientras se regenera un nuevo valor. Es una buena práctica establecer este valor si usa la opción:expires_in
.
2.2.1 Connection Pool Options
Por defecto, MemCacheStore
yRedisCacheStore
usan una sola conexión
por proceso. Esto significa que si está utilizando Puma u otro servidor con subprocesos,
puede tener varios subprocesos esperando a que la conexión esté disponible.
Para aumentar la cantidad de conexiones disponibles, puede habilitar la conexión
agrupación.
Primero, agregue la gema connection_pool
a su Gemfile:
gem 'connection_pool'
A continuación, pase las opciones :pool_size
y / o :pool_timeout
al configurar el almacén de caché:
config.cache_store = :mem_cache_store, "cache.example.com", { pool_size: 5, pool_timeout: 5 }
:pool_size
: esta opción establece el número de conexiones por proceso (el valor predeterminado es 5).:pool_timeout
: esta opción establece el número de segundos de espera para una conexión (el valor predeterminado es 5). Si no hay conexión disponible dentro del tiempo de espera, se generará unTimeout::Error
.
2.2.2 Custom Cache Stores
Puede crear su propio almacén de caché personalizado simplemente extendiendo
ActiveSupport::Cache::Store
e implementando los métodos apropiados. De esta manera,
puede intercambiar cualquier cantidad de tecnologías de almacenamiento en caché en su aplicación Rails.
Para usar un almacén de caché personalizado, simplemente configure el almacén de caché en una nueva instancia de su clase personalizada.
config.cache_store = MyCacheStore.new
2.3 ActiveSupport::Cache::MemoryStore
Este almacén de caché mantiene las entradas en la memoria en el mismo proceso de Ruby. El caché
tienda tiene un tamaño acotado especificado enviando la opción :size
al
inicializador (el valor predeterminado es 32 Mb). Cuando la caché excede el tamaño asignado, un
se producirá la limpieza y las entradas utilizadas menos recientemente b
config.cache_store = :memory_store, { size: 64.megabytes }
Si está ejecutando varios procesos del servidor Ruby on Rails (que es el caso si está usando Phusion Passenger o el modo en clúster de Puma), entonces su servidor Rails Las instancias de proceso no podrán compartir datos de caché entre sí. Este caché store no es apropiado para grandes implementaciones de aplicaciones. Sin embargo, puede funcionan bien para sitios pequeños y de poco tráfico con solo un par de procesos de servidor, así como entornos de desarrollo y prueba.
Los nuevos proyectos de Rails están configurados para utilizar esta implementación en el entorno de desarrollo de forma predeterminada.
Dado que los procesos no compartirán datos de caché al usar :memory_store
,
no será posible leer, escribir o caducar manualmente el caché a través de la consola Rails.
2.4 ActiveSupport::Cache::FileStore
Este almacén de caché utiliza el sistema de archivos para almacenar entradas. La ruta al directorio donde se almacenarán los archivos de la tienda debe especificarse al inicializar la caché.
config.cache_store = :file_store, "/path/to/cache/directory"
Con este almacén de caché, varios procesos de servidor en el mismo host pueden compartir un cache. Este almacén de caché es apropiado para sitios de tráfico bajo a medio que son servido de uno o dos anfitriones. Los procesos del servidor que se ejecutan en diferentes hosts comparta una caché mediante un sistema de archivos compartido, pero no se recomienda esa configuración.
Como la caché crecerá hasta que el disco esté lleno, se recomienda borre periódicamente las entradas antiguas.
Esta es la implementación de la tienda de caché predeterminada (en "#{root}/tmp/cache/"
) si
no se proporciona un config.cache_store
explícito.
2.5 ActiveSupport::Cache::MemCacheStore
Este almacén de caché utiliza el servidor "memcached" de Danga para proporcionar un caché centralizado para su aplicación. Rails usa la gema dalli
incluida por defecto. Esta es actualmente la tienda de caché más popular para sitios web de producción. Se puede utilizar para proporcionar un único clúster de caché compartido con un rendimiento y una redundancia muy altos.
Al inicializar la caché, debe especificar las direcciones para todos servidores memcached en su clúster. Si no se especifica ninguno, asumirá memcached se está ejecutando en localhost en el puerto predeterminado, pero este no es un ideal configuración para sitios más grandes.
Los métodos write
y fetch
en esta caché aceptan dos opciones adicionales que aprovechan las características específicas de Memcached. Puede especificar :raw
para enviar un valor directamente al servidor sin serialización. El valor debe ser una cadena o un número. Puede usar operaciones directas de Memcached como increment
y decrement
solo en valores sin procesar. También puede especificar :less_exist
si no desea que memcached sobrescriba una entrada existente.
config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com"
2.6 ActiveSupport::Cache::RedisCacheStore
La tienda de caché de Redis aprovecha el soporte de Redis para el desalojo automático cuando alcanza la memoria máxima, lo que le permite comportarse como un servidor de caché Memcached.
Nota de implementación: Redis no expira las claves de forma predeterminada, así que tenga cuidado de usar un servidor de caché Redis dedicado. No llene su servidor Redis persistente con datos de caché volátiles! Leer el Guía de configuración del servidor de caché de Redis en detalle.
Para un servidor Redis de solo caché, configure maxmemory-policy
en una de las variantes de allkeys.
Redis 4+ admite el desalojo menos utilizado (allkeys-lfu
), un excelente
elección predeterminada. Redis 3 y versiones anteriores deberían utilizar el desalojo utilizado menos recientemente (allkeys-lru
).
Establezca tiempos de espera de lectura y escritura en caché relativamente bajos. Regenerando un valor en caché suele ser más rápido que esperar más de un segundo para recuperarlo. Ambos leen y escribir tiempos de espera predeterminados a 1 segundo, pero se puede establecer más bajo si su red es constantemente de baja latencia.
De forma predeterminada, el almacén de caché no intentará volver a conectarse a Redis si el la conexión falla durante una solicitud. Si experimenta desconexiones frecuentes, es posible que desee habilitar intentos de reconexión.
Las lecturas y escrituras de caché nunca generan excepciones; simplemente devuelven nil
en su lugar,
comportarse como si no hubiera nada en el caché. Para medir si su caché es
golpeando excepciones, puede proporcionar un error_handler
para informar a un
servicio de recopilación de excepciones. Debe aceptar tres argumentos de palabras clave: método
,
el método de almacenamiento de caché que se llamó originalmente; return
, el valor que
se devolvió al usuario, normalmente nil
; y excepción
, la excepción que
fue rescatado.
Para comenzar, agregue la gema redis a su Gemfile:
gem 'redis'
Puede habilitar el soporte para más rápido hiredis biblioteca de conexión agregando adicionalmente su envoltorio ruby a su Gemfile:
gem 'hiredis'
La tienda de caché de Redis requerirá y usará automáticamente hiredis si está disponible. No más se necesita configuración.
Finalmente, agregue la configuración en el archivo config/environment/*.rb
relevante:
config.cache_store = :redis_cache_store, { url: ENV['REDIS_URL'] }
Un almacén de caché de Redis de producción más complejo puede verse así:
cache_servers = %w(redis://cache-01:6379/0 redis://cache-02:6379/0)
config.cache_store = :redis_cache_store, { url: cache_servers,
connect_timeout: 30, # Defaults to 20 seconds
read_timeout: 0.2, # Defaults to 1 second
write_timeout: 0.2, # Defaults to 1 second
reconnect_attempts: 1, # Defaults to 0
error_handler: -> (method:, returning:, exception:) {
# Report errors to Sentry as warnings
Raven.capture_exception exception, level: 'warning',
tags: { method: method, returning: returning }
}
}
2.7 ActiveSupport::Cache::NullStore
Esta implementación de almacenamiento de caché está destinada a usarse solo en entornos de desarrollo o prueba y nunca almacena nada. Esto puede ser muy útil en el desarrollo cuando tiene código que interactúa directamente con Rails.cache
pero el almacenamiento en caché puede interferir con la posibilidad de ver los resultados de los cambios de código. Con este almacén de caché, todas las operaciones de fetch
y read
darán como resultado un error.
config.cache_store = :null_store
3 Cache Keys
Las claves utilizadas en una caché pueden ser cualquier objeto que responda a cache_key
o
to_param
. Puede implementar el método cache_key
en sus clases si lo necesita
para generar claves personalizadas. Active Record generará claves basadas en el nombre de la clase
y registro de identificación.
Puede utilizar hashes y matrices de valores como claves de caché.
# This is a legal cache key
Rails.cache.read(site: "mysite", owners: [owner_1, owner_2])
Las claves que use en Rails.cache
no serán las mismas que las que realmente usa con
el motor de almacenamiento. Pueden modificarse con un espacio de nombres o modificarse para adaptarse
limitaciones de la tecnología backend. Esto significa, por ejemplo, que no puede guardar
valores con Rails.cache
y luego intente extraerlos con la gema dalli
.
Sin embargo, tampoco debe preocuparse por exceder el límite de tamaño de Memcached o
violar las reglas de sintaxis.
4 Conditional GET support
Los GET condicionales son una característica de la especificación HTTP que proporciona una forma para que los servidores web le digan a los navegadores que la respuesta a una solicitud GET no ha cambiado desde la última solicitud y se puede extraer de forma segura de la caché del navegador.
Funcionan utilizando los encabezados HTTP_IF_NONE_MATCH
y HTTP_IF_MODIFIED_SINCE
para pasar tanto un identificador de contenido único como la marca de tiempo de la última vez que se cambió el contenido. Si el navegador realiza una solicitud donde el identificador de contenido (etag) o la última modificación desde la marca de tiempo coincide con la versión del servidor, entonces el servidor solo necesita enviar una respuesta vacía con un estado no modificado.
Es responsabilidad del servidor (es decir, nuestra) buscar la última marca de tiempo modificada y el encabezado if-none-match y determinar si enviar o no la respuesta completa. Con el soporte de obtención condicional en Rails, esta es una tarea bastante fácil:
class ProductsController < ApplicationController
def show
@product = Product.find(params[:id])
# If the request is stale according to the given timestamp and etag value
# (i.e. it needs to be processed again) then execute this block
if stale?(last_modified: @product.updated_at.utc, etag: @product.cache_key_with_version)
respond_to do |wants|
# ... normal response processing
end
end
# If the request is fresh (i.e. it's not modified) then you don't need to do
# anything. The default render checks for this using the parameters
# used in the previous call to stale? and will automatically send a
# :not_modified. So that's it, you're done.
end
end
En lugar de un hash de opciones, también puede simplemente pasar un modelo. Rails usará los métodos updated_at
y cache_key_with_version
para configurar last_modified
y etag
:
class ProductsController < ApplicationController
def show
@product = Product.find(params[:id])
if stale?(@product)
respond_to do |wants|
# ... normal response processing
end
end
end
end
Si no tiene ningún procesamiento de respuesta especial y está usando el mecanismo de renderizado predeterminado (es decir, no está usando respond_to
o llamando a renderizar usted mismo), entonces tiene un ayudante fácil en fresh_when
:
class ProductsController < ApplicationController
# This will automatically send back a :not_modified if the request is fresh,
# and will render the default template (product.*) if it's stale.
def show
@product = Product.find(params[:id])
fresh_when last_modified: @product.published_at.utc, etag: @product
end
end
A veces queremos almacenar en caché la respuesta, por ejemplo, una página estática, que nunca obtiene
Caducado. Para lograr esto, podemos usar el ayudante http_cache_forever
y haciendo
por lo que el navegador y los proxies lo almacenarán en caché indefinidamente.
De forma predeterminada, las respuestas almacenadas en caché serán privadas, almacenadas en caché solo en la web del usuario.
navegador. Para permitir que los proxies almacenen en caché la respuesta, establezca public: true
para indicar
que pueden entregar la respuesta en caché a todos los usuarios.
Con este ayudante, el encabezado last_modified
se establece en Time.new(2011, 1, 1).utc
y el encabezado expires
se establece en 100 años.
Utilice este método con cuidado ya que el navegador / proxy no podrá invalidar la respuesta almacenada en caché a menos que la caché del navegador se borre a la fuerza.
class HomeController < ApplicationController
def index
http_cache_forever(public: true) do
render
end
end
end
4.1 Strong v/s Weak ETags
Rails genera ETag débiles de forma predeterminada. Los ETag débiles permiten semánticamente equivalentes respuestas para tener los mismos ETag, incluso si sus cuerpos no coinciden exactamente. Esto es útil cuando no queremos que la página se vuelva a generar para cambios menores en cuerpo de respuesta.
Los ETag débiles tienen un W /
principal para diferenciarlos de los ETag fuertes.
W/"618bbc92e2d35ea1945008b42799b0e7" → Weak ETag
"618bbc92e2d35ea1945008b42799b0e7" → Strong ETag
A diferencia de ETag débil, ETag fuerte implica que la respuesta debe ser exactamente la misma y byte a byte idéntico. Útil cuando se realizan solicitudes de rango dentro de un archivo grande de video o PDF. Algunas CDN solo admiten ETag potentes, como Akamai. Si es absolutamente necesario generar un ETag fuerte, puede hacerlo de la siguiente manera.
class ProductsController < ApplicationController
def show
@product = Product.find(params[:id])
fresh_when last_modified: @product.published_at.utc, strong_etag: @product
end
end
También puede configurar el ETag fuerte directamente en la respuesta.
response.strong_etag = response.body # => "618bbc92e2d35ea1945008b42799b0e7"
5 Caching in Development
Es común querer probar la estrategia de almacenamiento en caché de su aplicación
en modo de desarrollo. Rails proporciona el comando rails dev:cache
para
activar / desactivar fácilmente el almacenamiento en caché.
$ bin/rails dev:cache
Development mode is now being cached.
$ bin/rails dev:cache
Development mode is no longer being cached.
6 References
Comentarios Sobre el Contenido
Las guías de rieles se administran y publican en latinadeveloper/railsguides.es en GitHub.
Si lee esta guía y encuentra algún texto o código incorrecto que le interese, no dude en enviar una solicitud de extracción en el repositorio anterior. Consulte el archivo README en GitHub para saber cómo enviar una solicitud de extracción. Please contribute if you see any typos or factual errors.