form_with使用時の「ActionController :: InvalidAuthenticityToken」エラー

Sep 16 2020

私は次のようなフォームを持っています:

  <%= 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 %> 

フォーム送信直後:

ノート:

  • これは(APIではなく)アプリで発生しているため、セッションが重要であるため、CSRF保護をオンのままにしておく必要があります。
  • この問題は、クロム、シークレット、およびサファリで発生します。
  • 別のユーザーでログインしてCookieをクリアしてみました(古いトークンが原因の場合)

エラーメッセージのいくつか:

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'

更新

フォームの最後の作業バージョンに戻しました。これは上記とまったく同じですが、がありません, local: true。それからそれは突然働きます!(エラーなし)。

私はlocal: true(またはremote: false)単にajaxフォームの送信をオフにすると思いました。だから、なぜそれが違いを生むのか(またはCSRFと関係があるのか​​)理解できません、これらの2つの側面は無関係であるように見え、これらの2つの概念が互いに影響を与える理由は明らかではありません

アップデート2

私は後で、以前は手つかずだった別のフォームでもこのエラーが発生したことに気付きました。それは決して変更されていませんでした。Chromeシークレットで試してみたところ、エラーが発生しました。30分後(コードを変更せずに)同じブラウザーで再試行しましたが、機能しました。この(非常に)奇妙な振る舞いは、セッション、Cookie、またはキャッシングに関係していると私に思わせます。さらに何かを学んだら報告します

アップデート3

アプリケーションコントローラーに追加するSarahのソリューションを読んだ後protect_from_forgery prepend: true(前と後の両方で試しましたbefore_action :authenticate_user!)、同じエラーメッセージがログに表示され、POSTリクエストは実行されませんが、アプリはホームページにリダイレクトされます。つまり、POST時に次のように表示されます。

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)

アップデート4

railsフラグメントキャッシュを手動でクリアしようとしました(を使用Rails.cache.clear )。ただし、結果はフラグメントキャッシュをクリアする前後でまったく同じです。

回答

2 SarahMarie Sep 17 2020 at 06:46

私はこのようなものにprotect_from_forgery prepend: true遭遇し、ApplicationControllerそれを解決するためにユーザー認証の前に追加したことを覚えています。

1 stevec Sep 17 2020 at 20:18

TL; DR:2週間のデバッグ試行の後、ターボリンクをオフにしたところ、問題は解決しました。

ターボリンクをオフにする以外に、別の解決策が(ここで言及されている)これをに追加しているようですapplication.js

$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });

前の答え

問題は再発し続けました。次の6つのことを試しましたが、まだ修正されていません

1.フラグメントキャッシュをクリアします

Rails.cache.clear(キャッシュをクリアするため警告します。sidekiqジョブなども削除します)。これにより、古いトークンが削除され、ブラウザでアプリを更新すると通常の状態に戻り、フォームを送信する必要があります(単純な「再送信」は機能しないため、フォームページに戻り、更新してから送信すると、作業)

2.ページのハードリフレッシュ

cmd+ opt+jを押して開発者コンソールを表示し、更新を右クリックして[キャッシュを空にしてハードリロード]を選択します

3.サイトのCookieを削除します

URLのすぐ左にある小さなアイコンを右クリックします(httpsを使用している場合はロック、httpを使用している場合は文字「i」になります)。リストされている各カテゴリ(「Cookie」、「サイト設定」など)に移動し、それらをすべて削除します

4.同じサイトを指す他のURLのCookieを削除します

たとえば、サイトがでwww.example.com、herokuでホストされている場合はwww.example.herokuapp.com、その2番目のURLのCookieも削除します。

5.ローカルホストのCookieを削除します

念のためローカルホストCookieを削除しました

6.クロムの完全に分離されたインスタンスでのテスト