Error "ActionController :: InvalidAuthenticityToken" al usar form_with
Tengo un formulario que se parece a esto:
<%= form_with(url: star.starname, method: :post, local: true) do |f| %>
<% star.availabilities.each do |avail| %>
<%= f.label avail.time_slot %>
<%= radio_button_tag(:time_slot, avail.time_slot) %> <br>
<% end %>
<%= f.submit "Create" %>
<% end %>
Inmediatamente después del envío del formulario:
Notas:
- Esto ocurre en una aplicación (no en una API), por lo que las sesiones son importantes, por lo que la protección CSRF debe dejarse activada.
- El problema ocurre en Chrome, Incognito y Safari.
- Intenté iniciar sesión con diferentes usuarios y borrar las cookies (en caso de que fuera causado por un token obsoleto )
Algunos más mensajes de error:
Started POST "/talljohn" for ::1 at 2020-09-16 10:06:21 +1000
Processing by StarsController#book as HTML
Parameters: {"authenticity_token"=>"P++4a+giwUBqZgCLfMwqKpMu0EGitd8zTOi5RWsnxpKlNcjiuU6hd3ebbIC/IOxlL74RJIvrq+yDuA1ZtfcvFw==", "time_slot"=>"2020-09-16 01:00:00 UTC", "commit"=>"Create", "starname"=>"talljohn"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 655)
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:215:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:247:in `handle_unverified_request'
devise (4.7.2) lib/devise/controllers/helpers.rb:255:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:242:in `verify_authenticity_token'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:428:in `block in make_lambda'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:200:in `block (2 levels) in halting'
actionpack (6.0.3.2) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:201:in `block in halting'
Actualizar
Volví a la última versión de trabajo del formulario, que era exactamente igual a la anterior pero sin ella , local: true. ¡Entonces de repente funciona! (sin errores).
Pensé local: true(o remote: false) simplemente desactiva el envío de formularios ajax. Entonces no entiendo por qué eso haría alguna diferencia (o tiene algo que ver con CSRF), parece que esos dos aspectos no están relacionados y no está claro por qué estos dos conceptos tendrían algún efecto entre sí.
Actualización 2
Más tarde me di cuenta de que otra forma de trabajo previamente intacta también producía este error. No se había cambiado de ninguna manera. Lo probé en incógnito de Chrome y produjo el error. Media hora después (sin cambiar ningún código) lo intenté de nuevo en el mismo navegador y funcionó. Este comportamiento (muy) extraño me hace pensar que tiene que ver con sesiones, cookies o caché. Informaré si descubro algo más
Actualización 3
Después de leer la solución de Sarah agregando protect_from_forgery prepend: trueal controlador de la aplicación (lo intenté antes y después before_action :authenticate_user!), aparece el mismo mensaje de error en los registros, la solicitud POST no se procesa, pero la aplicación redirige a la página de inicio. Es decir, al POST veo:
Can't verify CSRF token authenticity.
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 444)
Started GET "/users/sign_in" for ::1 at 2020-09-17 21:08:42 +1000
Processing by Devise::SessionsController#new as HTML
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Redirected to http://localhost:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.5ms | Allocations: 1900)
Actualización 4
Intenté borrar manualmente la caché de fragmentos de rieles (con Rails.cache.clear ). Pero el resultado es exactamente el mismo antes / después de borrar la caché de fragmentos.
Respuestas
Recuerdo que me encontré con algo como esto y agregué protect_from_forgery prepend: trueantes de cualquier autenticación de usuario para ApplicationControllerresolverlo.
TL; DR: después de 2 semanas de intentos de depuración, apagué los turboenlaces y el problema desapareció .
Aparte de apagar los turboenlaces, otra solución parece ser (mencionada aquí ) agregando esto aapplication.js
$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });
Respuesta anterior
El problema siguió resurgiendo. He intentado las siguientes seis cosas, pero todavía no lo he solucionado.
1. Limpiar la caché de fragmentos
Rails.cache.clear( advertencia porque borra el caché, también eliminará cosas como trabajos sidekiq, etc.). Esto eliminará el token obsoleto y la actualización de la aplicación en el navegador devolverá las cosas a la normalidad, y el formulario debería enviarse (un simple 'reenvío' no funcionará, así que vuelva a la página del formulario, actualice, luego envíe y debería trabajo)
2. Actualización completa de la página
Presione cmd+ opt+ jpara abrir la consola del desarrollador, luego haga clic derecho en actualizar y seleccione 'Vaciar caché y recargar duro'
3. Eliminar las cookies del sitio
Haga clic con el botón derecho en el ícono diminuto a la izquierda inmediata de la URL (será un candado si usa https, o la letra 'i' si usa http). Vaya a cada una de las categorías enumeradas (por ejemplo, 'Cookies', 'Configuración del sitio', etc.) y elimínelas todas
4. Elimina las cookies de otras URL que apuntan al mismo sitio.
Por ejemplo, si su sitio está www.example.comalojado en heroku en www.example.herokuapp.com, elimine también las cookies de esa segunda URL.
5. Eliminar cookies para localhost
Eliminé las cookies de localhost solo para estar seguro
6. Pruebas en instancias de cromo completamente aisladas