Błąd „ActionController :: InvalidAuthenticityToken” podczas używania form_with
Mam formularz, który wygląda tak:
<%= 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 %>
Natychmiast po przesłaniu formularza:
Uwagi:
- Dzieje się tak w aplikacji (nie w API), więc sesje są ważne, dlatego ochrona CSRF musi być włączona.
- Problem występuje w Chrome, incognito i safari.
- Próbowałem zalogować się z różnymi użytkownikami i wyczyścić pliki cookie (na wypadek, gdyby było to spowodowane nieaktualnym tokenem )
Więcej informacji o błędzie:
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'
Aktualizacja
Powróciłem do ostatniej działającej wersji formularza, która była dokładnie taka sama jak powyżej, ale bez , local: true. Wtedy nagle działa! (bez błędów).
Pomyślałem local: true(lub remote: false) po prostu wyłącza przesyłanie formularza Ajax. Więc nie rozumiem, dlaczego miałoby to coś zmienić (lub ma cokolwiek wspólnego z CSRF), wydaje się, że te dwa aspekty są niezwiązane i nie jest jasne, dlaczego te dwie koncepcje miałyby na siebie jakikolwiek wpływ
Zaktualizuj 2
Później zdałem sobie sprawę, że inny nietknięty poprzednio działający formularz również spowodował ten błąd. Nie został w żaden sposób zmieniony. Wypróbowałem to w chrome incognito i spowodowało to błąd. Pół godziny później (bez zmiany kodu) spróbowałem ponownie w tej samej przeglądarce i zadziałało. To (bardzo) dziwne zachowanie sprawia, że myślę, że ma to coś wspólnego z sesjami, plikami cookie lub pamięcią podręczną. Oddam raport, jeśli dowiem się czegoś więcej
Zaktualizuj 3
Po przeczytaniu dodania rozwiązania Sarahprotect_from_forgery prepend: true do kontrolera aplikacji (próbowałem zarówno przed, jak i po before_action :authenticate_user!), ten sam komunikat o błędzie pojawia się w dziennikach, żądanie POST nie jest wykonywane, ale aplikacja przekierowuje na stronę główną. To znaczy po POST widzę:
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)
Zaktualizuj 4
Próbowałem ręcznie wyczyścić pamięć podręczną fragmentów szyn (za pomocą Rails.cache.clear ). Ale wynik jest dokładnie taki sam przed / po wyczyszczeniu pamięci podręcznej fragmentów.
Odpowiedzi
Pamiętam, że wpadłem na coś takiego i dodałem protect_from_forgery prepend: trueprzed jakimkolwiek uwierzytelnieniem użytkownika do ApplicationControllerrozwiązania tego problemu.
TL; DR: po 2 tygodniach prób debugowania wyłączyłem turboliny i problem zniknął .
Oprócz wyłączenia turbolinków, wydaje się, że innym rozwiązaniem jest ( tutaj ) dodanie tegoapplication.js
$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });
Poprzednia odpowiedź
Problem powracał. Wypróbowałem następujące sześć rzeczy, ale nadal tego nie naprawiłem
1. Wyczyść pamięć podręczną fragmentów
Rails.cache.clear( ostrzeżenie, ponieważ czyści pamięć podręczną, usunie również takie rzeczy, jak zadania sidekiq itp.). Spowoduje to usunięcie nieaktualnego tokena, a odświeżenie aplikacji w przeglądarce przywróci normalne działanie, a formularz powinien zostać przesłany (proste „ponowne przesłanie” nie zadziała, więc wróć do strony formularza, odśwież, a następnie prześlij i powinno praca)
2. Twarde odświeżanie strony
Naciśnij cmd+ opt+, jaby wywołać konsolę programisty, a następnie kliknij prawym przyciskiem myszy na odświeżenie i wybierz `` Opróżnij pamięć podręczną i mocno załaduj ponownie ''
3. Usuń pliki cookie witryny
Kliknij prawym przyciskiem myszy małą ikonę po lewej stronie adresu URL (będzie to blokada, jeśli używasz https lub litera „i”, jeśli używasz http). Przejdź do każdej z wymienionych kategorii (np. „Pliki cookie”, „Ustawienia witryny” itp.) I usuń je wszystkie
4. Usuń pliki cookie z innych adresów URL, które kierują do tej samej witryny
Na przykład, jeśli Twoja witryna to www.example.comi jest hostowana na heroku pod adresem www.example.herokuapp.com, usuń pliki cookie również z tego drugiego adresu URL
5. Usuń pliki cookie dla localhost
Dla pewności usunąłem pliki cookie localhost
6. Testowanie w całkowicie izolowanych przypadkach chromu