やりたかったこと
form送信後にJS側で何かしらの処理をしたい。
方法
fetchAPIのコールバックチェーンで行うことができる。
turbolinks
や rails-ujs
は使用しないので、 remote: true
を使ったAjax通信とも異なるやり方。
「form送信後のJS処理」を、
当初 form.submit() ~ setTimeout()
のような感じで書いたが、実行順序が担保されなかったので書き直した。
ポイント
fetch
では
-
credentials
に'same-origin'
-
body
にnew FormData(form)
を指定。
= f.submit
や %button{ type: 'submit' }
を使うと Railsによってリクエストが飛ばされてしまうので、%button{ type: 'button' }
を使って送信ボタンをクリックしたときにJavaScriptを呼び出すようにしている。
サンプル
あまりサンプルがなかった気がするのでさらっと残す。
送信ボタンを押した後に二度押せないようにする処理も入れてるが、もっとちゃんとした書き方はあるのかも。
const userForm = document.getElementById('user-form');
const submitBtn = document.getElementById('submit-btn');
submitBtn.addEventListener('click', () => {
submitBtn.textContent = '送信中...';
submitBtn.disabled = true;
fetch('/users', {
method: 'POST',
credentials: 'same-origin',
body: new FormData(userForm),
}).then(response => {
// 送信後の処理があればここに書く
}).catch(error => {
// 例外処理
});
});
= form_with(model: @user, id: 'user-form') do |f|
= f.text_field :name
= f.text_field :mail
%button{ type: 'button', id: 'submit-btn' }
送信
追記
コントローラ側でリクエストを受け取るアクションに、 protect_from_forgery
を適切に使うととりあえずリクエストを送信できるようになる
が、CSRF対策をちゃんとやるなら、fetch
のパラメータに headers: { 'X-CSRF-Token': csrfToken }
を付与する必要な場合がある。
jQueryを使っていると rails-ujs がよしなにやってくれるが、Vanilla.js で書く場合は Rails 側からCSRF のトークンを取ってくる必要がある。
詳しくは以下。
- 今さらjquery-railsがcsrfトークンをいい感じにしてくれていたことを知った
- RailsでCSRFを無効にせずにAjaxからRESTなAPIを叩く
- Rails で CSRF トークンの検証を制御する
- Rails の API モードで CSRF 対策機能を実装する
これが一番良さそう
追記2
ajax
イベントをキャッチして、フォーム送信を制御する方法もある模様。