2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Ruby on RailsAdvent Calendar 2024

Day 6

パスワードの変更画面で入力する確認用のパスワードをStimulusでチェック

Posted at

RailsアプリでDeviseを利用してユーザー認証をしています。パスワードの変更画面ではこれまでのパスワード、新しく設定するパスワード、新しく設定するパスワード(確認)の3つのテキストフォームがあります。

確認用のパスワードが間違っていた場合に画面遷移してエラーを出力してもよいのですが、Stimulusでチェックしてみることにしました。

Stimulusのコントローラーを作成

rails generate stimulus password_validation

新しく設定するパスワードとパスワード(確認)が一致しないときの挙動はいくつか考えられるのですが、今回は一致しないときにはボタンをクリックできないようにしました。

app/javascript/controllers/password_validation_controller.rb
// password_validation_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["password", "confirmation", "submit"]

  connect() {
    this.validatePasswords()
  }

  validatePasswords() {
    const password = this.passwordTarget.value
    const confirmation = this.confirmationTarget.value

    if (password !== confirmation) {
      this.confirmationTarget.setCustomValidity("Passwords do not match")
    } else {
      this.confirmationTarget.setCustomValidity("")
    }

    this.submitTarget.disabled = !this.confirmationTarget.checkValidity()
  }
}

パスワードの入力画面

app/views/devise/registrations/edit.html.erb
<div class="card mb-3">
  <div class="card-header">
    <%= t("views.change_password") %>
  </div>
  <div class="card-body" data-controller="password-validation">
    <%= form_for(resource, as: resource_name, url: registration_path(resource_name),
          html: { method: :put }) do |f| %>
      <%= render "devise/shared/error_messages", resource: resource %>

      <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
        <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
      <% end %>

      <div class="row g-3 mb-3">
        <div class="col-4 text-end">
          <%= f.label :current_password, class: "col-form-label" %>
        </div>
        <div class="col-8">
          <%= f.password_field :current_password, class: "form-control",
                placeholder: t("activerecord.attributes.user.current_password"),
                autocomplete: "current-password", required: true %>
        </div>
      </div>

      <div class="row g-3 mb-3">
        <div class="col-4 text-end">
          <%= f.label :password, class: "col-form-label" %>
        </div>
        <div class="col-8">
          <%= f.password_field :password, class: "form-control",
                placeholder: t("activerecord.attributes.user.password"),
                autocomplete: "new-password",  minlength: 10, required: true,
                "data-password-validation-target": "password",
                "data-action": "input->password-validation#validatePasswords" %>
        </div>
      </div>

      <div class="row g-3 mb-3">
        <div class="col-4 text-end">
          <%= f.label :password_confirmation, class: "col-form-label" %>
        </div>
        <div class="col-8">
          <%= f.password_field :password_confirmation, class: "form-control",
                placeholder: t("activerecord.attributes.user.password_confirmation"),
                autocomplete: "new-password",  minlength: 10, required: true,
                "data-password-validation-target": "confirmation",
                "data-action": "input->password-validation#validatePasswords" %>
        </div>
      </div>

      <%= f.submit class: "btn btn-primary col-4 offset-4 mt-1",
            "data-password-validation-target": "submit" %>
    <% end %>
  </div>
</div>

動作確認

新しく設定するパスワードとパスワード(確認)が一致しないとボタンをクリックできない状態になっています。

スクリーンショット

まだまだ迷いながらですが、Hotwire時代に適応できるよう頑張っていこうと思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?