結論
HTMLのフォーム送信ボタンに使用される、
二重サブミットを防止する便利なオプションです。
本記事では、
- data-disable-withの挙動
- data-disable-withが使えないケース
- data-disable-withが使えない時の代替案
をざっくりと説明していきたいと思います。
data-disable-withの挙動
はじめに、data-disable-withとは
- Railsの
rails-ujs
1というJavaScriptライブラリによって提供される - フォーム送信ボタンにオプションとして指定することが出来る
- 指定されたボタンは、一度クリックされるとボタンが無効となる
といった特徴から、
railsでフォーム送信を行う際の二重サブミット2対策として使われています。
以下はform_withにdata-disable-with属性を使用する際のサンプルコードです。
<%= form_with url: '/your_url', method: :post do |form| %>
<%= 中略 %>
<%= form.submit 'Submit', data: { disable_with: 'Submitting...' } %>
<% end %>
上記のように書くことで、サブミット送信後、
ローディング中に指定した「Submitting...」という文言が送信ボタンに表示されます。
「Submitting...」という文言が表示されている間は、ボタンは無効になります。
そのため、複数回連続で送信を押す二重サブミットを防ぐことが出来ます。
data-disable-withが使えないケース
以下に、data-disable-withが使えないときに考えられる原因をいくつか紹介します。
- そもそもrails-ujsをインストールしていない
- 他の外部ライブラリとの兼ね合い
- 他のJSとの兼ね合い
- data-disable-withつきの送信ボタンが、同じ画面上に複数個ある
本記事では、上記の理由の中から私が実際に直面した
「そもそもrails-ujsをインストールしていない」「他の外部ライブラリとの兼ね合い」
の2つを詳しく解説します。
そもそもrails-ujsをインストールしていない
rails-ujsというのは、rails5.0~6.1での標準ライブラリです。
しかし、私が使用していたrails7.0では、
rails-ujsは標準ライブラリから除外されていたため、
上記サンプルコードのように記述しても動作しませんでした。
そのため、rails5.0~6.1以外のバージョンでrails-ujsを使用したい場合は、
gem 'rails-ujs'
というように、明示的にライブラリをインストールする必要があります。
他の外部ライブラリとの兼ね合い
私が使用しているrails7.0には、標準ライブラリとしてturbo, stimulusが採用されています。
特にturboは、デフォルトでajaxのフォーム送信を操作するライブラリのため、
rails-ujsの操作とバッティングしてうまく動作しない場合が出てきます。
結論、rails7.0でdata-disable-withの機能のためだけに(あるいはそれをきっかけにして)、
あえてrails-ujsを入れるのはオススメしません。
では、代わりにどのようなコードで二重サブミットを防ぐようにするべきでしょうか。
data-disable-withが使えない時の代替案
今回はJavaScriptのonClick処理を使い、
サブミットボタン押下時にdisable属性を付与するやり方を取りました。
<%= form_with url: '/your_url', method: :post do |form| %>
<%= 中略 %>
<%= form.button 'Submit', type: 'button', onclick: "clickEvent(event);" %>
<% end %>
<script>
function clickEvent(e) {
e.target.disabled = true;
e.target.value = 'Submitting...';
const form = e.target.closest('form');
form.submit();
}
</script>
これにより、
- 送信後、ボタン操作が無効となる
- ボタンに「Submitting...」と表示される
- 上記の処理を行った上でサブミットする
という要件を満たしたJSの操作が実現しました。
フォーム送信には欠かせない二重サブミット対策ですが、
data-disable-withを使用する際はまず、
railsのバージョンとrails-ujsインストールの有無を確認してみてください!
追記(2024/06/14):rails7.0でdata-disable-withを実現する
rails7.0に伴い導入されたturboの仕組みを使って、
より簡単にdata-disable-withを実現する方法がありましたので紹介します。
これは、turboの処理とCSSを組み合わせることで実現可能です。
<%= form_with url: '/your_url', method: :post do |form| %>
<%= 中略 %>
<%= form.button do %>
<span class="show-when-enabled">Submit</span>
<span class="show-when-disabled">Submitting...</span>
<% end %>
<% end %>
button {
.show-when-enabled { display: initial; }
.show-when-disabled { display: none; }
&[disabled] {
.show-when-enabled { display: none; }
.show-when-disabled { display: initial; }
}
}
rails7.0を使っている人はこちらも参考にしてみてください!
参考記事
Railsガイド「3.4 入力を自動で無効にする」
ザリガニが見ていた...。「:disable_withで処理中を明確にして二重送信を防止」
Qiita「同じform内にsubmitボタンが複数ある際のdisable_withの使い方」
ボクココ「rails-ujs と form_with の使い方」
GoRails(youtube動画)「Migrating from Rails UJS to Hotwire: Data Confirm, Method, and Disable With」