text_field_tag - Ruby on Rails forma el almacenamiento en caché de la página incluyendo authenticity_token
select_tag rails (5)
Como publicó Matchu, puedes implementar el punto dos de esta publicación (el mismo enlace que publicó, pero también se encontró a través de mi Google). Esto agrega una dependencia en JavaScript, que puede o no ser algo que desea.
Alternativamente, usted podría mirar en caché de fragmentos . Esto le permite almacenar en caché ciertas partes de una página, pero aún así generar las partes dinámicas (como formularios con tokens de autenticidad). Usando esta técnica, podría almacenar en caché el resto de la página, pero generar un nuevo formulario para cada solicitud.
Una solución final (pero la menos favorable) es deshabilitar el token de autenticidad para esa acción específica. Puede hacer esto agregando lo siguiente al principio del controlador que genera ese formulario:
protect_from_forgery :except => [:your_action]
También puede desactivar protect_from_forgery para todo el controlador agregando lo siguiente al principio:
skip_before_filter :verify_authenticity_token
Tengo un formulario simple de Ruby on Rails que incluye una clave de autenticidad. Desafortunadamente, me perdí eso cuando la página almacena en caché esta página, entonces el token de autenticidad se vuelve inválido. Sin embargo, me alegro de haberlo descubierto.
¿Cómo resuelves el almacenamiento en caché en tal caso?
Como una solución más general, también puede reemplazar todas las identidades de autenticación en caché con las actuales:
module CacheHelper
def cache_with_updated_csrf(*a, &block)
Nokogiri::HTML::DocumentFragment.parse( capture { cache(*a,&block) } ).tap do |doc|
doc.css("input[name=#{request_forgery_protection_token}]").each { |e| e[''value''] = form_authenticity_token }
end.to_html.html_safe
end
end
Y use = cache_with_updated_csrf do
lugar de - cache do
en sus vistas. Felicitaciones a Bernard Potocki por la idea.
No parece ser un problema bien resuelto. El punto dos en esta publicación del blog describe cómo realizar la tarea utilizando jQuery, pero eso introduce una dependencia de Javascript. Sopesar sus opciones, supongo.
Puede representar una etiqueta personalizada en el marcado almacenado en caché y reemplazarla con el formulario representado en cada solicitud.
module CacheHelper
# Our FORM is deeply nested in the CACHED_PARTIAl, which we
# cache. It must be rendered on every request because of its
# authenticity_token by protect_from_forgery. Instead of splitting up the
# cache in multiple fragments, we replace a special tag with the custom
# form.
def cache_with_bla_form(resource, &block)
form = nil
doc = Nokogiri::HTML::DocumentFragment.parse( capture { cache("your_cache_key",&block) } )
doc.css(''uncachable_form'').each do |element|
form ||= render(:partial => ''uncachable_form'', :resource => resource)
element.replace form
end
doc.to_html
end
end
Y, en su opinión, simplemente genera una etiqueta uncachable_form vacía.
<%- cache_with_bla_form resource do %>
# cachable stuff..
<uncachable_form />
# more cachable stuff
<%- end %>
Sí, esto puede ser considerado como un Hack, pero no aflojará la protección de la falsificación, no necesita JS y disminuirá la ganancia de rendimiento por el almacenamiento en caché solo un poco. Creo que alguien implementó un patrón similar como un Rack Middleware.
Seguí la solución general de Niklas Hofer, pero descubrí que su implementación no coincidía con la semántica exacta del ayudante de caché de Rails. Es decir, intentó devolver el HTML almacenado en caché desde el ayudante, en lugar de escribirlo en el búfer usando safe_concat
, que es lo que hace el ayudante de Rails.
El uso del ayudante de Rails es así:
- cache do
= something
Mientras que su solución requería esta sintaxis:
= cache_with_updated_csrf do
= something
Por coherencia, preferiría que estos funcionen de la misma manera. Por eso utilicé esta sintaxis:
- cache_form do
= something
Aquí está mi implementación. También omitirá el almacenamiento en caché cuando el almacenamiento en caché está deshabilitado, como lo hace el ayudante de Rails.
module CacheHelper
# Cache a form with a fresh CSRF
def cache_form(name = {}, options = nil, &block)
if controller.perform_caching
fragment = fragment_for(name, options, &block)
fragment_with_fresh_csrf = Nokogiri::HTML::DocumentFragment.parse( fragment ).tap do |doc|
doc.css("input[name=#{request_forgery_protection_token}]").each { |e| e[''value''] = form_authenticity_token }
end.to_html
safe_concat fragment_with_fresh_csrf
else
yield
end
nil
end
end