19

Estoy usando CloudFlare CDN en mi aplicación Rails 3.1. Cloudflare es un CDN que funciona en el nivel de DNS. En el primer golpe a un activo estático, CloudFlare lo carga desde tu aplicación y luego lo almacena en su CDN. Solicitudes futuras de esa carga de activos desde el CDN en lugar de su aplicación.¿Cómo evito que Rails 3.1 guarde en caché los activos estáticos en Rails.cache?

El problema que estoy teniendo es que si se configura el almacenamiento en caché del controlador en verdad:

config.action_controller.perform_caching = true 

permite al Rack middleware :: Cache. Como Rails establece una configuración de control de caché predeterminada para los activos estáticos, esos activos se escriben en el almacén de Rails.cache. Como resultado, mi almacén de caché (en mi caso, redis) se está llenando con activos estáticos con la url como la clave de hash.

Lamentablemente, no puedo desactivar los encabezados de control de caché de activos estáticos sin afectar la forma en que Cloudflare y los navegadores de mis usuarios almacenan en caché los activos. No puedo desactivar el almacenamiento en caché del controlador o pierdo el almacenamiento en caché de la página/acción/fragmento. El mismo resultado si elimino el middleware Rack :: Cache.

¿Alguien tiene alguna otra idea?

Actualización: He abierto un ticket en GitHub here.

+0

Cuando dice activos estáticos ¿quiere decir solo los archivos que genera Sprockets? –

+0

Sí, lo hago. Con el hash agregado a los nombres de los archivos. –

Respuesta

7

El póster original quería evitar que los activos estáticos entren en la caché general de Rails, lo que les llevó a querer deshabilitar Rack :: Cache. En lugar de hacer esto, la mejor solución es configurar Rack :: Cache para usar un caché separado del caché general de Rails.

Rack :: El caché debe configurarse de forma diferente para el almacenamiento de entidades frente al almacenamiento de metadatos. Rack :: Cache tiene dos áreas de almacenamiento diferentes: tiendas meta y entidad. El metastore mantiene información de alto nivel sobre cada entrada de caché, incluidos los encabezados de solicitud y respuesta HTTP. Esta área almacena pequeños fragmentos de datos a los que se accede a alta frecuencia. La tienda de la entidad almacena en caché el contenido del cuerpo de la respuesta, que puede ser una cantidad relativamente grande de datos, aunque se accede a ella con menos frecuencia que el metastore.

La siguiente configuración almacena en caché la información del metastore en memcached pero el cuerpo real de los activos en el sistema de archivos.

Usando joya memcached:

config.action_dispatch.rack_cache = { 
    :metastore => 'memcached://localhost:11211/meta', 
    :entitystore => 'file:tmp/cache/rack/body', 
    :allow_reload => false 
} 

Usando joya Dalli

config.action_dispatch.rack_cache = { 
    :metastore => Dalli::Client.new, 
    :entitystore => 'file:tmp/cache/rack/body', 
    :allow_reload => false 
} 

Por cierto esta configuración es la recomendación para Heroku: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31

8

Después de mucha experimentación, he terminó haciendo esto en mi config/application.rb:

if !Rails.env.development? && !Rails.env.test? 
    config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public' 
end 

Lo que esto hace es añadir un estante estático :: middleware bastidor antes de peticiones para acumular :: Cache. El middleware Stack Rack :: sirve urls con un prefijo correspondiente a un directorio raíz. Aquí estoy dando config.assets.prefix como mi prefijo url que por defecto es '/ assets'. Estoy estableciendo la raíz en el directorio 'public'.

Las solicitudes de este camino:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

debe encontrar en este archivo:

pública/activos/jquery-e8da439bbc8fd345e34ac57c6a216318.min .js

Esto debería servir a cualquier activo directamente fuera del directorio público/de activos en lugar de golpear a Rails :: Ca che en absoluto, lo que evitará que almacene los activos en el almacén de caché de Rails. Esto solo funcionará si ejecuta los activos de rake: precompilación en producción, de lo contrario no habrá activos precompilados en 'public/assets'.

+0

un lado aleatorio: ¿cómo se muestra su identificación de activo en el nombre del archivo? – Kevin

+0

¿Ha configurado 'config.assets.precompile' para incluir todos los archivos que desea precompilar? –

+0

@Kevin puede establecer 'config.action_controller.perform_caching = true' en su production.rb http://guides.rubyonrails.org/asset_pipeline.html#in-production – Schneems

1

Otra manera de resolver el mismo problema y este problema es utilizar el ActionDispatch :: estático middleware en lugar de rack :: estático como sigue:

if !Rails.env.development? && !Rails.env.test? 
    config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, 'public', config.static_cache_control 
end 

Cuál es la diferencia entre la cremallera :: estático y ActionDispatch: : Estático preguntas?

  • Rack :: Static toma una matriz de prefijos de url para verificar contra el URL de solicitud. Entonces, en nuestro caso, solo buscará archivos si la ruta de solicitud comienza con '/ assets'.

  • ActionDispatch :: Static verificará la existencia del archivo en 'public' en cada solicitud GET/HEAD, independientemente de la ruta.

  • Rack :: Static no comprueba primero el archivo, llama a Rack :: File.new en el archivo, por lo que si no existe devolverá un 404, no pasará la solicitud la cadena de middleware.

  • Si ActionDispatch :: Static no encuentra el archivo en su ruta, continuará por la cadena de middleware del rack (el resto de la pila de Rails).

Al final, sea cual sea ActionDispatch :: estático no encuentra en 'público' sólo va a pasar hacia abajo a la pila de rieles. Así que Rails terminará sirviendo los activos que ActionDispatch :: Static no puede encontrar. Esto resuelve mi problema de los activos que Rack :: Cache no encuentra, pero también requiere más recursos, ya que cada solicitud activará una verificación de archivos.

+0

Cuando dice" cada solicitud activará una comprobación de archivos " - ¿Te refieres a cada solicitud a la aplicación, o solo solicitudes al público? –

+0

Además, en el primer punto, ¿quiso decir ActionDispatch :: Static? –

+1

No, está bien. Rack :: Static toma una variedad de prefijos de url. La llave incluso se llama "urls". –

3

Se puede desactivar el almacenamiento en caché de la tubería de activos archivos mientras deja otro almacenamiento en caché en su lugar con:

config.assets.cache_store = :null_store 

Eso debería evitar que los piñones guarden algo en el caché.

+0

Esto funcionó para mí en Rails 3.2 después de que todas las respuestas anteriores solo me dieron la mitad. ¡Gracias! –

Cuestiones relacionadas