LoginSignup
9
2

結論

HTMLのフォーム送信ボタンに使用される、
二重サブミットを防止する便利なオプションです。

本記事では、

  • data-disable-withの挙動
  • data-disable-withが使えないケース
  • data-disable-withが使えない時の代替案

をざっくりと説明していきたいと思います。

data-disable-withの挙動

はじめに、data-disable-withとは

  • Railsのrails-ujs1というJavaScriptライブラリによって提供される
  • フォーム送信ボタンにオプションとして指定することが出来る
  • 指定されたボタンは、一度クリックされるとボタンが無効となる

といった特徴から、
railsでフォーム送信を行う際の二重サブミット2対策として使われています。

以下はform_withにdata-disable-with属性を使用する際のサンプルコードです。

sample.html
<%= form_with url: '/your_url', method: :post do |form| %>
  <%= 中略 %>
  <%= form.submit 'Submit', data: { disable_with: 'Submitting...' } %>
<% end %>

上記のように書くことで、サブミット送信後、
ローディング中に指定した「Submitting...」という文言が送信ボタンに表示されます。

image.png
これを押すと
image.png
こうなる

「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属性を付与するやり方を取りました。

alter_sample.html
<%= 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を組み合わせることで実現可能です。

turbo_sample.html
<%= 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 %>
turbo_sample.scss
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」

  1. UJSとは「Unobtrusive(控えめな)JavaScript」の略で、
    rails-ujsとはrailsでJavaScriptの処理を簡単に行えるようにする機能のこと。

  2. フォーム送信後の通信している間、送信ボタンが有効であることで、複数回送信してしまうこと。これにより注文の重複やフォームの意図しない誤送信が起こる。

9
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
2