【jQuery】RailsでValidation Pluginを使った動的なバリデーションチェックの実装 〜導入編〜

# はじめに
本記事がQiitaでの初投稿となります。
jQueryのプラグインを使って動的なバリデーションチェック機能を実装しました。
実装手順とRailsで使用する場合の注意点をシェアします。

# 開発環境
Ruby 2.5.1
Rails 5.0.7.2
jQuery 3.4.1
jQuery Validation Plugin 1.19.1
Haml 5.1.2
Sass 3.7.4

# jQuery Validation Pluginとは
jQuery Validation Pluginはバリデーションチェックが実装できるjQueryのプラグインです。

公式サイト：https://jqueryvalidation.org/

# やりたいこと
+ 入力フォームにユーザー情報を入力する際にリアルタイムにバリデーションをチェック
+ バリデーションエラーがある場合はエラーをリアルタイムに表示
+ バリデーションがNGの場合は入力欄が赤色、OKの場合は緑色に変更

# なぜjQuery Validation Pluginを選んだのか？
バリデーションチェックを実装するにあたり、実装方法を検討しました。
他にも以下の方法があります。
①[RailsのActive Record バリデーション](https://railsguides.jp/active_record_validations.html)
②[HTMLのフォーム検証機能](https://developer.mozilla.org/ja/docs/Learn/HTML/Forms/Form_validation)
③[HTML5 + JavaScriptによるFormバリデーション](https://liginc.co.jp/345545)

プラグインなどを有効活用でき、動的にバリデーションチェックできることを主軸に検討し、
jQueryプラグインでフロントエンドでの第１チェックを行い、Railsのバリデーションでバックエンド側の最終チェックを行う方法を選びました。


# 完成イメージ
　**バリデーションNGの場合**
![f84fd46c54185fe33c48155f5c351a86.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/54c03eb4-64b7-f734-6262-d8f7a8bc5d72.gif)
　**バリデーションNG→OKの場合**
![89c9be89713460808c27152edc4ec222.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/c3248541-f0c1-9cb1-53d5-232f8013d973.gif)

　**バリデーションOKの場合**
![e20855f932d4782f531643e312954f0a.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/64c70add-9f99-4b2e-cc96-f98afd2f9d2d.gif)

# 実装手順
### 1. プラグインの導入

[CDN](https://www.1-firststep.com/archives/2142)でも導入できるそうですが、上手くいかなかったため、下記手順で導入しました。

**1.1 公式サイトにアクセス**
![スクリーンショット 2020-01-04 0.41.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/00b17901-b2ac-7c0b-b606-6c46a5ccca77.png)
**1.2 ダウンロードページへ**
<img width="704" alt="スクリーンショット 2020-01-04 0.42.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/a01cffa4-bead-5bac-4c13-ffe823147465.png">
**1.3 最下段からzipファイルをダウンロード**
<img width="811" alt="スクリーンショット 2020-01-04 0.43.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481946/45ca4b17-c1d6-f54c-f495-34b327b7b9d9.png">
**1.4 下記のJSファイルをアプリのディレクトリに保存**

+ jquery-validation-1.19.1/dist/jquery.validate.min.js (※1)
+ jquery-validation-1.19.1/src/localization/messages_ja.js (※2)

※1 : 必須
※2 : 標準メッセージを日本語化したい場合のみ

### 2. HTMLファイルの作成

下記のように入力フォームのform_forとf.text_filedなどの各入力欄にidを割り振ります。
(例： id: "signup-form", id: "name" etc.)
BEMが長くて読みにくいですが、ご容赦ください。

**Railsでの注意点：HTMLではname属性値を付けないようにしましょう。(理由は後述します。)**

私は最初、name属性値を指定していてバリデーションチェックが動作しませんでした。

```registration.html.haml
= form_for(@user, url: phone_signup_index_path, method: :get, html: {class: "registration__main__form", id: "signup-form"}) do |f|
  %div.registration__main__form__content
    %div.registration__main__form__content__group
      = f.label :name, "ニックネーム", class: "registration__main__form__content__group__label" 
      %span.registration__main__form__content__group__require 必須
      = f.text_field :name, class: "registration__main__form__content__group__input", placeholder:"例）テスト太郎", id: "name"
    %div.registration__main__form__content__group
      = f.label :email, "メールアドレス", class: "registration__main__form__content__group__label"
      %span.registration__main__form__content__group__require   必須
      = f.email_field :email, class:"registration__main__form__content__group__input", placeholder:"PC・携帯どちらでも可", id: "email"
    %div.registration__main__form__content__group
      = f.label :password, "パスワード", class: "registration__main__form__content__group__label"
      %span.registration__main__form__content__group__require  必須
      = f.password_field :password, class:"registration__main__form__content__group__input", placeholder:"7文字以上の半角英数字", id: "password"
      %p.registration__main__form__content__group__input__info  ※ 英字と数字の両方を含めて設定してください。
      %div.registration__main__form__content__group
        = f.label :password_confirmation, "パスワード(確認)", class: "registration__main__form__content__group__label"
        %span.registration__main__form__content__group__require  必須
        = f.password_field :password_confirmation, class:"registration__main__form__content__group__input", placeholder:"7文字以上の半角英数字", id: "password_confirmation"
```

### 3. Javascriptファイルの作成

次に下記のようにJavascriptファイルを作成します。
ファイル名は任意です。

```jquery.validate.handler.user.js
$(function () {
  // メソッドの定義
  var methods = {
    email: function (value, element) { // メールアドレスの正規表現
      return this.optional(element) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/i.test(value);
    },
    password: function (value, element) { // パスワードの正規表現
      return this.optional(element) || /^(?=.*?[a-z])(?=.*?\d)[a-z\d]{8,100}$/i.test(value);
    },
  }
  // メソッドの追加
  $.each(methods, function (key) {
    $.validator.addMethod(key, this);
  });
  // バリデーションの実行
  $("#signup-form").validate({
    // ルール設定
    rules: {
      "user[name]": {
        required: true // ニックネームの入力有無チェック
      },
      "user[email]": {
        required: true, // メールアドレスの入力有無チェック
        email: true // メールアドレスの正規表現チェック
      },
      "user[password]": {
        required: true, // パスワードの入力有無チェック
        password: true // メールアドレスの正規表現チェック
      },
    },
    // エラーメッセージの定義
    messages: {
      "user[name]": {
        required: "ニックネームを入力してください"
      },
      "user[email]": {
        required: "メールアドレスを入力してください",
        email: "フォーマットが不適切です"
      },
      "user[password]": {
        required: "パスワードを入力してください",
        password: "英字と数字両方を含むパスワードを入力してください"
      },
    },
    errorClass: "invalid", // バリデーションNGの場合に追加するクラス名の指定
    errorElement: "p", // エラーメッセージの要素種類の指定
    validClass: "valid", // バリデーションOKの場合に追加するクラス名の指定
    }
  });
  // 入力欄をフォーカスアウトしたときにバリデーションを実行
  $("#name, #email, #password").blur(function () {
    $(this).valid();
  });
});
```

基本的な記述方法は下記の記事を参考にさせていただきました。
[【jQuery入門】validate()の使い方と独自ルールの設定方法！](https://www.sejuku.net/blog/44470)
[jQuery Validation 簡単にフォームをチェック バリデーション](https://sys-guard.com/post-14579/)
[フォームの入力値を検証するjQuery Validation Pluginの使い方](https://into-the-program.com/jquery-validation-plugin/)

メールアドレスとパスワードの正規表現はデフォルトのルールでも実装可能です。

#### Railsでの注意点

通常の使い方だとrules:の中にname属性値を指定しますが、下記の記事の通り、Railsの場合は少し通常と異なります。
[[Rails]「jQueryValidationプラグイン」を使用してフォームのバリデーションを実装](https://qiita.com/NT90957869/items/84ca64d145f8ef9c4fdd#name%E5%B1%9E%E6%80%A7%E3%81%AB%E3%81%8C%E5%85%A5%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88)

ページのソースを確認するとname属性値は"user[name]"となっています。
このname属性値をrules:の中で指定するとバリデーションチェックが動作します。

```html
<input class="クラス名" placeholder="例）メルカリ太郎" id="name" type="text" name="user[name]" />
<input class="クラス名" placeholder="PC・携帯どちらでも可" id="email" type="email" name="user[email]" />
<input class="クラス名" placeholder="7文字以上の半角英数字" id="password" type="password" name="user[password]" />
```

このRails特有のname属性値の指定の仕方についての記事が少なく途中で手詰まりました。
いろいろ調べたところ以下記事で明確な記載がありました。
[JQuery validate in Rails applications](https://tudip.com/blog-post/jquery-validate-rails-applications/)

>
Please note that in rails, name of an element is created as form[name] instead of name only. If you are creating a form for creating a new user and fields in this form are Email first_name, last_name etc then name of these fields is being created as user[emal], user[first_name], user[last_name] resp. While using these name of an elements as key you have to keep in mind to use them in qoutes i.e
“user[email]” or your jquery will be unable to understand what this name belongs to.

```
'user[name]': {required : true}
```

一部を訳すとRailsではname属性値がuser[email]となっているため、"user[email]"としないとjQueryがそのname属性が何に属しているかを認識しないと記述がありました。

#### 入力欄をフォーカスアウトした時に動作させる

通常の使い方ですとsubmitボタンが押されたタイミングでバリデーションチェックが動作します。
入力欄をフォーカスアウトした時などに動作させたい場合は、下記のように実行のタイミングを指定します。

```js
  // 入力欄をフォーカスアウトしたときにバリデーションを実行
  $("#name, #email, #password").blur(function () {
    $(this).valid();
  });
```
下記の記事を参考させていただきました。
[jquery.validate.jsでvalidateチェックタイミングを指定する](https://confrage.jp/jquery-validate-js%E3%81%A7validate%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B/)

### 4. CSSファイル作成

バリデーションNGもしくはOKの時に追加されるクラス名を独自に指定できるので、
CSSで枠線を指定します。

```js
    errorClass: "invalid", // バリデーションNGの場合に追加するクラス名の指定
    validClass: "valid", // バリデーションOKの場合に追加するクラス名の指定
```

```registration.scss
.registration {
  &__main {
    // 〜省略〜
    &__form {
      // 〜省略〜
      &__content {
      // 〜省略〜
        &__group {
          // 〜省略〜
          &__input.invalid { // バリデーションNGの場合に枠線を赤色に変更
            border: #ea352d 1px solid;
          }
          &__input.valid {
            border: seagreen 1px solid; // バリデーションNGの場合に枠線を緑色に変更
          }
        }
      }
    }
  }
}
// エラーメッセージ
#name-error, #email-error, #password-error {
  color: #ea352d;
  line-height: 1.5;
  font-size: 14px;
  margin-top: 8px;
}
// 入力欄をクリック時に枠線を水色に変更
input[type=text]:focus,
input[type=email]:focus,
input[type=password]:focus {
  outline: none;
  border-color: #0098E8;
}

```

# まとめ

jQuery Validation Pluginを用いて実行タイミングを指定すると動的なバリデーションチェックが実装可能です。

他にもselectタグのバリデーションなども実装しましたので別記事でまとめたいと思います。
記載内容に誤りなどございましたら、ご指摘いただけますと幸いです。


# 参考URL
https://jqueryvalidation.org/
https://www.sejuku.net/blog/44470
https://sys-guard.com/post-14579/
https://into-the-program.com/jquery-validation-plugin/
[[Rails]「jQueryValidationプラグイン」を使用してフォームのバリデーションを実装](https://qiita.com/NT90957869/items/84ca64d145f8ef9c4fdd#name%E5%B1%9E%E6%80%A7%E3%81%AB%E3%81%8C%E5%85%A5%E3%81%A3%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88)
[jquery.validate.jsでvalidateチェックタイミングを指定する](https://confrage.jp/jquery-validate-js%E3%81%A7validate%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%99%E3%82%8B/)