好きなものだけ書く。ポジティブに。

好きなことを楽しく。プログラミング、写真、音楽、ガジェットとか。

Rails7 で button_to の data-confirm の挙動が変わって data.confirm から form.data.confirm に変わってました

おつかれさまです!のぶじゃすです。

最近Rails7でWebアプリケーションを開発しているのですが、削除の処理などの後戻りができないときや、事前に確認が必要な処理を書く際にブラウザのconfirm機能を使って確認ダイアログを出す処理を出したい場面がありました。

Rails7でこの機能の処理が変わってしまっていてハマりました。今回はある程度詳細な理由も調べてみました。

想定以上にアタフタ困ってしまった動画はこちら

実は動画撮影中にこの変更にハマってしまいました。まんまとハマって困りまくり焦りまくりの動画はこちらです。面白かったら高評価おねがいしますw


www.youtube.com

Rails7より前の button_to で confirm を出す方法

Railsでは button_to などで簡単にconfirmを出す機能がありました。

<% button_to "削除", any_path(any), { method: :delete, data: { confirm: "本当に削除してもいいですか?" } } %>

のように書くことで確認ダイアログが表示されていました。

Rails7 ではこれだと出ない

Rails7ではこの方法では確認ダイアログが表示されず、そのまま処理されてしまいます。これでは簡単に削除できすぎてしまいます。

そこでいくつか調べた所、 解決策を見つけました。

Rails7 で button_to で confirm を出す方法

<%= button_to "削除", rabbit_weight_path(@rabbit, weight), { method: :delete, form: { data: { turbo_confirm: "本当に削除しますか?" } } } %>

data: { confirm: "確認" }form: { data: { turbo_confirm: "確認" } } に直す事で正しく表示されます。

挙動としてはこれで正しくなりましたがなぜなのかはよく分かりません。どういう処理でこれが動作しているのか少し調べてみました。

2023/02/15 追記: form をつけなくても confirmturbo_confirm にすると動く

id:JunichiIto さんにコメントを頂きました。ありがとうございます!

該当のPull Requestはこちらです Make data-turbo-confirm work with multiple submitters inside a form by feliperaul · Pull Request #564 · hotwired/turbo · GitHub

このPull Requestがmergeされた Turbo 7.2 (turbo-rails 1.3) 以降では <form data-turbo-confirm="xxx" でも動きますが、 <button data-turbo-confirm="xxx" のようにbuttonタグに設定する形でも反応してくれるようになりました。

具体的にはこんな感じです

<%= button_to "削除", rabbit_weight_path(@rabbit, weight), { method: :delete, data: { turbo_confirm: "本当に削除しますか?" } } %>

これはありがたいですね。出力されたHTMLを見た時に見つけやすくなりますし、1つのformの中で複数のボタンがある場合で別のconfirmを出したい場合などにも使いやすそうです。

form: でくくると何が起こるのか

button_to の第3引数で form: { data: を設定するとそれ自体が form タグで囲まれます。そして form タグのアトリビュートに data-turbo-confirm が設定されます。

具体的には

erbに下記のように書くと

<%= button_to "削除", rabbit_weight_path(@rabbit, weight), { method: :delete, form: { data: { turbo_confirm: "本当に削除しますか?" } } } %>

HTMLとしてはこのようにレンダリングされます。

<form data-turbo-confirm="本当に削除しますか?" class="button_to" method="post" action="/rabbits/1/weights/2">
  <input type="hidden" name="_method" value="delete" autocomplete="off">
  <button type="submit">削除</button>
  <input type="hidden" name="authenticity_token" value="..........................." autocomplete="off">
</form>

そしてどうやってconfirm処理が動いているのか

Rails7ではturboが動いているため、以前のバージョンと変わったようです。

ということで turbo のコードを読んでみましょう。

  1. confirm 処理を探して読んでみた
  2. form_submission.ts にそれっぽいコードを見つけました
  3. FormSubmission というクラスでは formElement を constructor で受け取ります
  4. confirmationMessagedata-turbo-confirm を探します
  5. needsConfirmation では confirmationMessage が存在した場合に true を返します
  6. needsConfirmationtrue の場合には confirmMethod が発火します
  7. confirmMethod ではJavaScript標準(ブラウザ標準?)の cofirm 処理を動かしています

この辺りの処理です

github.com

正しい対応っぽいので大丈夫そう

コードをざっと読んでみた所、特におかしな所はなく想定されている挙動のようだったのでこれで安心して開発が進められます。

アクセスありがとうございます🙇‍♂️

ここまで読んでいただき誠にありがとうございました。もしこの記事が役に立ったらはてブや、Twitterのフォローしていただけると大変喜びます😊

それではよいRails7ライフを!