Help us understand the problem. What is going on with this article?

Rails6 + devise + モーダルウィンドウでリアルタイムバリデーション機能を実装してみる

Rails6でsignup時にjquery-validation-engineを使ってリアルタイムにバリデーションをかけてチェックする

はじめに

そもそもリアルタイムバリデーションってなんやねん!笑
多分こんな感じです↓
Image from Gyazo

対象

  • ライブラリやプラグインに抵抗がない方
  • Rails6.0でdeviseを使ってモーダルウィンドウを表示してみたい方
  • 簡単にリアルタイムでバリデーションをかけてみたい方
  • 楽したい方(だいじ😁)

環境

Ruby v2.6.4
Rails v6.0.2.1
Haml v5.1.2

今回使用するもの

devise (gem)
Bootstrap4
jquery-validation-engine (プラグイン)

Rails6.0のインストール(既にインストールされている方は飛ばしておk)

こちらの記事を参考にyarnとRails6.0をインストール↓
https://qiita.com/sasakura_870/items/44baadd3546eae4554c1

yarnでBootstrap4をRailsに導入(既に導入されている方は飛ばしておk)

yarnコマンドでbootstrapとそれに依存しているjquery, popper.jsを追加

$ yarn add bootstrap jquery popper.js

jquery、popper.js をいつでも使用できるようにProvidePluginを設定する

config/webpack/environment.js
const {environment} = require('@rails/webpacker')
const webpack = require('webpack')

environment.plugins.append('Provide', new webpack.ProvidePlugin({
  $: 'jQuery',
  JQuery: 'jquery',
  Popper: ['popper.js', 'default']
}))

module.exports = environment

Bootstrapをインポート

app/javascript/packs/application.js
require("@rails/ujs").start()
require("@rails/activestorage").start()
require("channels")

~~ 省略 ~~

import 'bootstrap' # 追加
import "../stylesheets/application" # 追加

app/javascript/stylesheets/application.scssを作成し、その中にbootstrapのscssをインポート

app/javascript/stylesheets/application.scss
@import "~bootstrap/scss/bootstrap";

application.html.haml(erb) のstylesheet_link_tagstylesheet_pack_tagに変更する
※ 自分の環境はhamlを使っています。erbでも同様です
色々訳あって、turbolinksは外しています✋

app/views/layouts/application.html.haml
= stylesheet_pack_tag 'application'

これでjQueryBootstrapの準備が完了です!

deviseの導入

deviseはユーザー登録、ログイン機能を提供するgemです

以下手順

Gemfileにdeviseを記述

Gemfile
gem 'devise'

deviseをインストール
(もしサーバーが立ち上がっていたら一度切ってください)

$ bundle install

deviseのジェネレーターを生成

$ rails g devise:install

deviseのviewを生成

$ rails g devise:views

Userモデルをdeviseに紐づけて生成

$ rails g devise user

migrateする

$ rake db:migrate

トップページ用の適当なビューファイルを作成

$ rails g controller tops index

ルーティングを変更

routes.rb
Rails.application.routes.draw do
  devise_for :users
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  root "tops#index"
end

deviseのビューファイルをBootstrapを使ってスタイリング

signup時のビューを部分テンプレートにしたいので、app/views/devise/registrations/new.html.hamlapp/views/devise/registrations/_new.html.hamlにして、
以下のようにbootstrapを使ってモーダル表示させるようにする
(ここではidをsignUpModalとしてるが自分の好きな名前で良い)

app/views/devise/registrations/new.html.haml
.modal.fade#signUpModal{tabindex: "-1", role: "dialog", "aria-hidden": true}
  .modal-dialog{role: "document"}
    .modal-content
      .modal-header.d-block
        %h5.modal-title.text-center ユーザー登録
      .modal-body
        = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
          = render "devise/shared/error_messages", resource: resource
          .field.form-group
            = f.label :nickname
            %br/
            = f.text_field :nickname, autofocus: true, autocomplete: "nickname", class: "form-control"
          .field.form-group
            = f.label :email
            %br/
            = f.email_field :email, autofocus: true, autocomplete: "email", class: "form-control"
          .field.form-group
            = f.label :password
            - if @minimum_password_length
              %em
                (#{@minimum_password_length} characters minimum)
            %br/
            = f.password_field :password, autocomplete: "new-password", class: "form-control"
          .field.form-group
            = f.label :password_confirmation
            %br/
            = f.password_field :password_confirmation, autocomplete: "new-password", class: "form-control"
          .actions.form-group
            = f.submit "Sign up", class: "btn btn-primary form-control"

トップページを以下のようにマークアップ
リンクにnew.html.hamlで設定したidをdata属性で指定

index.html.haml
.jumbotron
 %h1.display-4 Title
 %h2.read this is a bootstrap jumbotron style
 %hr.my-4
 = link_to "モーダル", new_user_registration_path, class: "btn btn-primary btn-lg", type: "button", "data-toggle": "modal", "data-target": "#signUpModal"
 = render "devise/registrations/new"

これでリンクボタンを押すとsignup画面が上からフワ〜ンと現れるようになる

jquery-validation-engineの導入

リアルタイムにバリデーションをかけるためのjquery-validation-engineというプラグインを以下のGithubからダウンロードします↓
https://github.com/posabsolute/jQuery-Validation-Engine

Installationという項目のところに tar.gz 3.x.x or zip 3.x.x とあるので
zipファイルをダウンロードします
(linuxの方はtar.gzの方で)

展開したら中に入っている
jquery.validationEngine.js (プラグイン本体)
jquery.validationEngine-ja.js (プラグイン日本語化)

app/javascript/packsディレクトリに置く

次に
validationEngine.jquery.cssapp/javascript/stylesheetsディレクトリに置く

application.jsの設定

Rails6.0ではjavascriptファイルとcssファイルのコンパイルが従来のアセットパイプラインからwebpackerが標準になったため、ブラウザからjavascript、cssを読み込ませるための場所(エントリーポイント)が、app/javascript/packs/application.jsになっています。

よって、ここを基点としてjs、cssファイルなどを読み込んでいきます。
先程のjquery.validationEngine.jsjquery.validationEngine-ja.jsapp/javascript/packs/application.jsに以下のようにして読み込ませます

app/javascript/packs/application.js
require("@rails/ujs").start()
require("@rails/activestorage").start()
require("channels")
require("./jquery.validationEngine")  # 追加
require("./jquery.validationEngine-ja")  # 追加

import 'bootstrap'
import "../stylesheets/application"

stylesheets.scssの設定

validationEngine.jquery.cssvalidationEngine.jquery.scssに拡張子リネームし、以下にインポート

app/javascript/stylesheets/application.scss
@import "~bootstrap/scss/bootstrap";
@import "./validationEngine.jquery.scss";  # 追加

modal.jsを作成する

app/javascript/packs/modal.jsを作成し、以下のように記述

app/javascript/packs/modal.js
$(function(){

  $(".new_user").validationEngine({
    promptPosition: "inline"
  });


});

promptPositionでエラーメッセージの表示位置をinputの下に表示するようにしている

app/javascript/packs/application.jsmodal.jsを読み込ませる

app/javascript/packs/application.js
~~ 省略 ~~
require("./jquery.validationEngine-ja")
require("./modal")

これでバリデーションの準備が整いました!(長かった)

サインアップ画面にバリデーションを付与

以下がバリデーションを付与したソースコード

app/views/devise/registrations/_new.html.haml
~~ 省略 ~~
      .modal-body
        = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f|
          = render "devise/shared/error_messages", resource: resource
          .field.form-group
            = f.label :nickname
            %br/
            = f.text_field :nickname, autofocus: true, autocomplete: "nickname", class: "form-control validate[required]"
          .field.form-group
            = f.label :email
            %br/
            = f.email_field :email, autofocus: true, autocomplete: "email", class: "form-control validate[required, custom[email]]"
          .field.form-group
            = f.label :password
            - if @minimum_password_length
              %em
                (#{@minimum_password_length} characters minimum)
            %br/
            = f.password_field :password, autocomplete: "new-password", class: "form-control validate[required, minSize[6]]", id: "passwd"
          .field.form-group
            = f.label :password_confirmation
            %br/
            = f.password_field :password_confirmation, autocomplete: "new-password", class: "form-control validate[required, equals[passwd]]"
          .actions.form-group
            = f.submit "Sign up", class: "btn btn-primary form-control"

validate[required] --- 入力必須

= f.text_field :nickname, class: "form-control validate[required]"

custom[email] --- メールアドレスかチェック

= f.email_field :email, class: "form-control validate[required, custom[email]]"

minSize[10] --- 10文字以上であるかチェック

= f.password_field :password, class: "form-control validate[required, minSize[6]]"

equals[passwd] --- 同じ値であるかチェック

= f.password_field :password, class: "form-control validate[required, minSize[6]]", id: "passwd" # idを付与

idと同じかチェックする

= f.password_field :password_confirmation, class: "form-control validate[required, equals[passwd]]"

上記の条件で最低限のバリデーションはできると思います!

まとめ

久々にQiita書きました。ポートフォリオの改変をしていたときに、
signup画面をモーダルウィンドウ化してバリデーションをかけてみたいと思い記事を書いてみました。
少し長々となってしまいましたが、バリデーションっていってもjqueryのプラグイン入れるぐらいで特別なことは得にしていない感じです。
少し面倒なところといえば、Bootstrapの導入ぐらいでかね?
jqueryバリデーションは他にも色々な条件や機能があるみたいですので、時間があったら研究してみたいですね^^

参考記事

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした