Rails5でBootstrap4のフォームバリデーションを実装してみた(そして思いっきりハマった)

2020年4月3日Ruby on Rails, プログラミングBootstrap 4, form, Javascript, Programming, Rails 5, Ruby on Rails 5, Turbolinks 5, validation, バリデーション, フォーム, プログラミング

【経緯】
Rails 5 & Bootstrap 4 & turbolinks 5で思いっきりハマったので、メモっときます。
読み込みを早めるためにも、turbolinksは絶対と思っていたので、turbolinksはオフにしない方向で進めました。
思いっきり独学で勉強しているので、何か間違いがあったり、もっとスマートな方法などがあればご教示いただけると幸いです。

【実現したいこと】
・フォームでsubmitボタンを押されたときに、それぞれのフォームに赤枠や緑枠をつける
・エラーがあるとき、メッセージを該当フォームの下に表示する

【環境】
Rails 5.2.3
Bootstrap 4.1.3
tubolinks 5.2.0
devise 4.6.2
Bootstrap(@importの記述 etc.)やdeviseの初期設定は完了しているものとする。

【コード 1】
app/views/devise/registrations/new.html.erb(とりあえずdeviseを例にする)

# フォーム部分のごく一部のみ抜粋
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), :html => {class:"needs-validation", :novalidate => true}) do |f| %>
  <div class="form-group">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "email", class:'form-control', required: true %>
    <div class="invalid-feedback">
      メールアドレスを入力してください。
    </div>
  </div>

  <div class="actions">
  <%= f.submit "Sign up" %>
  </div>
<% end %>

【コード 2】
app/assets/javascripts/bootstrap_form.js

(function() {
  'use strict';

  window.addEventListener('turbolinks:load', function() {
    // カスタムブートストラップ検証スタイルを適用するすべてのフォームを取得
    var forms = document.getElementsByClassName('needs-validation');
    // ループして帰順を防ぐ
    var validation = Array.prototype.filter.call(forms, function(form) {
      form.addEventListener('submit', function(event) {
        if (form.checkValidity() === false) {
          event.preventDefault();
          event.stopPropagation();
        }
        form.classList.add('was-validated');
      }, false);
    });
  }, false);
})();


【必要と思われること】
・formに「needs-validation」クラスを付与する
・formに「novalidate」のブール値属性を付与する
・読み込ませるjavascriptの「window.addEventListener」の引数として、’load’ではなく、’turbo links:load’を用いる。
・フォームに「:required :true」などバリデーションをかけたい要素を付与する

【雑記】
半日ほど悩んだ末、答えにたどり着きました笑
RailsでJavascriptやstylesheetで色々制御してたらturbolinksが悪さをするって昔からよく話題になってますが、うまく付き合いたいものです。

bootstrapの公式サイトには”load”を引数としてとっている例しか記載がないので(当たり前)、URL直打ちしたらきちんと動くのに、リンクたどったり、ブラウザの戻るボタンとかでは全く動かない、1回目のsubmitは反応せず、2回目は赤枠だけ表示されてエラーメッセージが出ないなど、泥沼でしたw

冒頭にも記載しましたが、完全独学で学んでいるため、間違っている箇所、スマートじゃない箇所があればご指摘いただけると幸いです。