【Rails】パスワードの2回入力は不要。1回にしてマスキング解除機能を実装【jQuery】


環境

Ruby on Rails 5.2.4(gem 'devise'は不使用)
⇒ gem 'font-awesome-sass'を使用
jquery-rails 4.3.5
haml 5.1.2

前提

Webアプリケーションのユーザ新規登録画面で、確認の為にパスワードを2回入力させる事ってよくあると思うんですよ。
Railsの機能的にもpasswordとpassword_confirmationが合致しないとユーザ登録できない仕様になっていますし。

これに関してはpassword用の入力フォームを1つ用意し、
userをsaveさせる前にpasswordの値をpassword_confirmationにも代入する事で、確認用のpassword_confirmationフォームを省くことが可能です。

users_controller.rb
# 色々省略
  def create
    @user = User.create(user_params)
    @user.password_confirmation = user_params[:password] #ここでpasswordの値を代入する
    if @user.save
      session[:user_id] = @user.id
      redirect_to mypage_path
      flash[:notice] = "新規登録が完了しました"
    else
      flash[:alert] = @user.errors.full_messages
      redirect_to root_path
    end
  end

  private

    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end

ただ、このままだとユーザが新規登録の時に想定と異なる値を入力してしまった場合、間違いが分からないので再ログインができなくなりますよね?
ましてやその後のパスワードの変更手続きって面倒じゃないですか?

という疑問を感じたので調べてみた所、ちょっと古いですが下記記事でこの件によるユーザビリティの低下が示されてました。
https://uxmilk.jp/18568

じゃあどうするのって話ですが、上の記事内にもこの記事のタイトルにもありますが、マスキング(*マークでパスワードを非表示させる機能)を解除できる機能を作ればいいんですね。

完成形はこんな感じ

解決策

それっぽく見えるものなら何でもいいですが、今回はfontawesomeの目を使います。
こんなフォームがあったとします。

新規登録ビュー
-# 色々省略
.signup
  .signup-top
    新規登録
  .signup__contents
    = form_with(model: @user, url: users_path, local: true) do |f|
      -# ユーザアカウント
      .form-group
        = f.label :アカウント名, class: "form-title"
        %br
        = f.text_field :name, class: 'form-control'
        %br          
      -# メールアドレス
      .form-group
        = f.label :メールアドレス, class: "form-title"
        %br
        = f.email_field :email, class: 'form-control'
        %br
        -# パスワード
      .form-group
        = f.label :パスワード, class: "form-title"
        %br
        = f.password_field :password, class: 'form-control' #ここでマスキングが機能している
        .form-password
          = icon("fas","eye-slash") #目のアイコン。これのクリックで制御する
        %br
      .form-submit
        = f.submit "Signup", class: "btn-submit"

このpassword_field部分がChromeの検証では下記画像のように表記されています。

この赤枠で囲われているtype="password"によってマスキングが動いているんですね。という事で、jQueryで目のアイコンをクリックした時にtype="text"に変更する制御を与えましょう。
また分かりやすくする為、ついでに目のアイコンも一緒に切り替えます。

signup.js
  // パスワード入力フォームのスラッシュ目アイコンをクリックするとpassのマスキングを解除
  function eyeslashClick(){
    $(".fa-eye-slash").on("click", function(){
      $(".fa-eye").off("click") // offを設定しないとクリックした回数分だけ重複作動してしまう為
      let input = $(this).parents(".form-group").find("input");
      input.attr("type", "text"); // typeをpasswordに変更しマスキングを解除する
      $(this).removeClass(); // 目を消す
      $(this).addClass("fas fa-eye"); // アイコンをスラッシュのない目に置き換える
      eyeClick(); // 追加したfas fa-eyeにクリックイベントを付与
    });
  }
  // パスワード入力フォームの目アイコンをクリックするとpassをマスキング
  function eyeClick(){
    $(".fa-eye").on("click", function(){
      $(".fa-eye-slash").off("click") // offを設定しないとクリックした回数分だけ重複作動してしまう為
      let input = $(this).parents(".form-group").find("input");
      input.attr("type", "password"); // typeをpasswordに変更しマスキングを有効にする
      $(this).removeClass(); // 目を消す
      $(this).addClass("fas fa-eye-slash"); // アイコンをスラッシュのある目に置き換える
      eyeslashClick(); // 追加したfas fa-eye-slashにクリックイベントを付与
    });
  }
  // 目アイコンのクリックイベント呼び出しをデフォルト化
  eyeslashClick();
  eyeClick();

addClassで追加するだけでは置き換わった目のアイコンのクリックイベントが有効にならないので、忘れず付与しましょう。

総評

マスキングの解除を実装してもユーザが確認せず登録したら意味ないだろって?
そんなの知らぬ( ´_ゝ`)