Viewファイルの記述は以下
<%= link_to 'ログアウト', destroy_user_session_path, method: :delete, class: "logout" %>
method: :delete
の記述もあるのに「GET」で読み込まれているようです。???
引用
HARUPONdeさんの質問「投稿を削除したら、No route matches [GET] "/posts/1/destroy"がおきる」の解答にヒントがありました。ありがとうございました。
引用サイトの解答
link_toでGET以外のメソッドを投げるには、JavaScriptの力が必要です。
jquery-ujsあるいはrails-ujsといったJavaScriptライブラリは、読み込んでいますでしょうか。
引用サイト解答内の「JavaScriptの力」とは
Deviseを利用しているとたまに遭遇する問題で、原因は主にrails-ujsが読み込まれていないことのようです。
rails-ujsとは
#####ujsとは
railsガイドによれば「Unobtrusive(控えめな)JavaScript」からUJSだそうです。
※ひかめ目なとはrailsのコードとJavaScriptが正しくきちんと分離されていて「ぐいぐい食いこんで」きてJavaScriptがRailsコードに「混ざっていない」ということを「控えめ」と表現しているようです。
#####ujsの機能
ujsはリンククリック時に発火します。発火時セキュリティトークンという自サイトしか識別できない暗号を組み込みヘルパーに自動的に含まれるようにします。セキュリティトークンがマッチしない場合には、RailsはGET以外のリクエストを受け付けなくなります。
(きっと原因はこれ)
#####Get以外受け付けない理由
Railsがもつサイバー攻撃対策。名前はCross Site Request Forgeryといいます。外部サーバーから送信フォーム装ったリクエストを送るサイト攻撃に対する防御策です。決まったフォーム(付加されたセキュリティートークン)しか受け付けないように設定されています。この対策が「CSRF対策」だそうです。
*railsガイドを参照いたしました。
*「Ruby on Rails6超入門」秀和システム 掌田津邪乃著
参照①2.6 セッション固定攻撃
参照②はじめてのAjax
解決策1(私の場合)
私の場合、application.js(rails6.0)が全てコメントアウトだったので
require("@rails/ujs").start()
// require("turbolinks").start()
// require("@rails/activestorage").start()
// require("channels")
一部コメントアウトを外しました。
⇨require("@rails/ujs").start()をコメントアウトを解除
解決策2 link_toをbutton_toへ変更(リンク回避策)
(誤)
<%= link_to 'Delete', post, :method => :delete %>
(正)
<%= button_to 'Delete', post, :method => :delete %>
解決策3 セキュリティー対策であるCSRF対策を部分解除
※クロスサイトリクエストフォージェリ (CSRF)悪意のあるリンクやコードを仕込んでのサイト攻撃
destroyアクションを実施したいコントローラーに以下を追記する。
protect_from_forgery
を使います。
deleteを使用したいコントローラーからdestoryアクションを除外
(※今回はdevise_contollerなので編集できずに、こちらは無理でした)
protect_from_forgery :except => [:destroy]
参考 require("@rails/ujs").start( )について
####application.js内に記述があります。
(1)application.jsの場所の変更点
rails5.0→[プロジェクト]/app/assets/javascripts/application.js
rails6.0→[プロジェクト]/app/javascript/packs/application.js
(2)記述の仕方の変更点
//= require rails-ujs
//= require turbolinks
//= require_tree .
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels").