環境
ruby 2.6.5
Rails 6.0.4.1
sweetalert2(CDN)
実装したい機能
削除ボタンを押すと、ブラウザに警告アラートを出す。
OKを押すと削除され、Cancelを押すと、元の画面に戻る。
実装方法
削除リンク要素をgetElementByIdで取得。
クリックイベント内でpreventDefaultを使用し、削除イベントを中止。
sweetalert2を使用して、警告アラートを表示。
OKが押された場合のみ、削除処理を進める。
生じた問題
Railsのヘルパーメソッドであるlink_toで削除リンクを実装した場合、
JavascriptのpreventDefaultメソッドが効かず、
コントローラー処理が呼び出されてしまう。
→解決策へ飛ぶ
原因特定までの経緯
JSにdebugger、Railsコントローラー側にbinding.pryを記述し動かすと、
binding.pryも発動した。
コントローラーにリクエストが届いてしまっている。
つまり、イベントがキャンセルできていないと考えた。
ビューファイル抜粋
<td>
<%= link_to '削除', user_xxx_path(@user, xxx), method: :delete, id: "test" %>
</td>
コントローラー処理抜粋
def destroy
binding.pry
@xxx = Xxx.find_by(id: params[:id])
redirect_to user_path(current_user) if @xxx.destroy
end
JSファイル
function cation() {
//削除要素の取得
const test = document.getElementById("test");
// 削除ボタン押下でイベント発火
test.addEventListener('click',(e) => {
console.log("イベント読み込みok");
console.log(e.cancelable);
e.preventDefault();
debugger;
// 削除警告画面
Swal.fire({
title: '◯◯◯を削除します',
html: '過去の△△△も削除され、元に戻せません。',
footer: '<a href="#" class="text-blue-400 hover:bg-gray-200">◯◯◯の解約はこちら</a>',
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'OK',
allowOutsideClick: false,
}).then((result) => {
if (result.isConfirmed) {
Swal.fire(
'削除しました',
'Your file has been deleted.',
'success'
)};
});
});
};
window.addEventListener('load', cation);
また、下記についても確認がとれた。
・要素選択、イベント発火に問題はない
→console.log("イベント読み込みok")で、イベントの読み込みは確認できた。
・ aタグのリンク遷移はキャンセル可能なイベントである
→console.log(e.cancelable)の結果がtrueであった。
以上から、ヘルパーメソッド(link_to)に
オプションでメソッド(method: :delete)を指定しているのが
原因ではないかと考えた。
それを検証するために、メソッドオプションを指定しない編集リンクを作成した。
追加検証:ビュー抜粋
<%# ↓編集リンク追加 %>
<td>
<%= 編集', edit_user_subscription_path(@user, subs), id: "test-b", %>
</td>
<%# ↑編集リンク追加 %>
<td>
<%= link_to '削除', user_xxx_path(@user, xxx), method: :delete, id: "test" %>
</td>
追加検証:該当コントローラー
def edit
binding.pry
@xxx = Xxx.find_by(id: params[:id])
end
JSファイル
要素をtestからtest-bに変更
function cation() {
//削除要素の取得
const test-b = document.getElementById("test-b");
// 削除ボタン押下でイベント発火
test-b.addEventListener('click',(e) => {
console.log("イベント読み込みok");
console.log(e.cancelable);
e.preventDefault();
debugger;
~以下、略〜
これで編集リンクをクリックすると、
debuggerのみ動作し、binding.pryは動作しなかった。
コントローラーが動いていないことから、イベントが中止できたと判断した。
念の為、削除要素の(method: :delete)を消して同様のテストをしたところ、
編集リンクと同様の挙動となった。
つまり、ヘルパーメソッド(link_to)のオプション、
メソッドの指定(method: :delete)が原因だと特定できた。
また、ヘルパーメソッドを使用せずaタグで試したが同様の結果であった。
<a id="test-b" data-method="delete" href=<%= user_subscription_path(@user, xxx) %> >削除</a>
解決策
formを作り、a要素をinput要素(submit)に変更。
コントローラーのbinding.pryが動作せず、
JS側のdebuggerのみ動作することを確認。
無事イベントを中止にできた。
<%= form_with url: user_xxx_path(@user, xxx), method: :delete, local: true do |f| %>
<%= f.submit '削除', id: "test" %>
<% end %>
かなり古い2次情報記事だが、こちらを参考に上記方法を検証した。
→teratail
感想
MDN(addEventListener, preventDefault, a)、
Railsドキュメント(link_to)等を確認し、
オプションなどを試してみたがうまく行かなった。
また、そもそも一次情報に書かれいていることをを理解できなかった。
問題が解決できたこと、
またその結果実装を進められる結果は、良いが、
解決方法とそこまでの過程が課題アリだなと感じた。
具体的には、「イベントオブジェクト」について理解を深める必要がある。
簡易アクションとして、MDNでイベント入門を確認。
アプリ実装後、もっと詳しく見ていきたい。
***
オリアプ実装していると、「ちゃんと理解できていない」がよくわかる。
カリキュラム学習では、わかった!と思い、
課題実装でスムーズに実装できていても、
「自由に使いこなす」には至らないことを痛感する。
もっと理解したいポジティブな感情と同時に、
今、自力で答えを見つけられないくやしやだったり、
実装を優先するため、一時保留にする不安や焦りもわいてくる。
後者は、ネガティブな感情ではあるが、
何かに取り組み、対峙している結果とも捉えられる。
まだスタートラインにも立ってないし、
課題も改善も山積みだが、
今は、取り組み続けることにフォーカスしようと思った。
まずは、オリアプを完成させる!