はじめに
DeviseはRailsアプリケーションに認証機能を簡単に追加できる便利なGemです。
しかし、デフォルトの設定では以下のようにプロフィール更新とパスワード変更が同じフォームにまとめられています。
このままだと、ユーザーがプロフィール情報を更新するたびにパスワードも入力しなければならず、UX的にも良くないと思います。
そこで、今回はDeviseをカスタマイズして、プロフィール更新とパスワード変更を別々のフォームで行えるようにする方法について紹介します。
これにより、ユーザーがより使いやすいインターフェースを提供できるようになります。
前提条件
Railsアプリケーションの初期設定やDeviseの導入ができているboilerplate(ボイラープレート)で進めます。
もし手元にサンプルアプリケーションがない方は、以下の記事を参考にしてみてください。
現在のパスワード無しでプロフィール更新できるようにする
カスタマイズについては、Deviseのリポジトリのwikiに情報があるので、これを参考に進めたいと思います。
ポイントは以下になります。
- Devise::RegistrationsControllerを継承した独自のコントローラーを作る
- update_resourceメソッドをオーバーライドして、update_without_passwordメソッドを使う
- routes.rbのDeviseに関するルーティングを変更して、独自のコントローラーを使うようにする
- app/views/devise/registrations/edit.html.erbからパスワード関連の入力欄を削除
まずはDeviseを継承したコントローラーを作成します。
$ rails generate devise:controllers users
create app/controllers/users/confirmations_controller.rb
create app/controllers/users/passwords_controller.rb
create app/controllers/users/registrations_controller.rb
create app/controllers/users/sessions_controller.rb
create app/controllers/users/unlocks_controller.rb
create app/controllers/users/omniauth_callbacks_controller.rb
===============================================================================
Some setup you must do manually if you haven't yet:
Ensure you have overridden routes for generated controllers in your routes.rb.
For example:
Rails.application.routes.draw do
devise_for :users, controllers: {
sessions: 'users/sessions'
}
end
===============================================================================
routes.rbを変更して、独自のコントローラーを使うようにします。
devise_for :users, controllers: {
registrations: "users/registrations"
}
rails routesコマンドでルーティングを確認すると、registrationsに関連するものはdevise/registrationsではなく、users/registrationsを使用するように変わります。
続いて、Users::RegistrationsControllerを変更します。
# frozen_string_literal: true
class Users::RegistrationsController < Devise::RegistrationsController
protected
def update_resource(resource, params)
resource.update_without_password(params)
end
end
7行目のupdate_without_passwordメソッドを使うことで現在のパスワード無しでプロフィール更新できるようになります。
最後に、app/views/devise/registrations/edit.html.erbからパスワードの入力欄を削除します。
<h2>Edit <%= resource_name.to_s.humanize %></h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
<div class="field">
<%= f.label :first_name %><br>
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br>
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :email %><br>
<%= f.email_field :email, autocomplete: "email" %>
</div>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
<% end %>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
<h3>Cancel my account</h3>
<div>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %></div>
<%= link_to "Back", :back %>
これで現在のパスワード無しでもプロフィール更新ができるようになったはずです。
最終的な見た目は以下のようになります。
名前やメールアドレスを変更して、Updateを押したら成功するはずです。
もし、パスワードの変更もこのページで行いたいならcurrent_passwordの入力欄だけ削除すれば実現できます。
パスワード変更ページを追加する
新しくパスワードを変更するためのページを追加します。
こちらもwikiに情報があるので、参考にしたいと思います。
https://github.com/heartcombo/devise/wiki/How-To:-Allow-users-to-edit-their-password#solution-3
ページを追加するため、コントローラーとViewを作ります。
ここでは、追加するページのURLは、account/password/editにしたいと思います。
routes.rbに以下を追加します。
namespace :account do
resource :password
end
resourcesではなくresourceを使う理由は、ログインユーザーのパスワードに関するルーティングなので、特にidは不要でcurrent_userから取得できるためです。
コントローラーを追加します。
class Account::PasswordsController < ApplicationController
before_action :authenticate_user!
def show
redirect_to edit_account_password_path
end
def edit
end
def update
if current_user.update_with_password(password_params)
bypass_sign_in current_user
redirect_to account_password_path, notice: "Password updated successfully"
else
render :edit, status: :unprocessable_entity
end
end
private
def password_params
params.require(:user).permit(:current_password, :password, :password_confirmation)
end
end
showアクションはここでは編集ページにリダイレクトするだけにしています。ここは必要に応じてカスタマイズしてもらえたらと思います。
13行目のbypass_sign_inメソッドを使うことで、パスワードを変更した後もログイン状態を維持することができます。もしログアウトさせたい場合は、ここは不要です。
続いて、コントローラーに対応するViewを追加します。
ここでは編集ページだけ追加します。
<h2>Edit Password</h2>
<%= form_with(model: current_user, url: account_password_path, html: { method: :put }) do |f| %>
<%= render "devise/shared/error_messages", resource: current_user %>
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br>
<%= f.password_field :current_password, autocomplete: "current-password" %>
</div>
<div class="field">
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br>
<%= f.password_field :password, autocomplete: "new-password" %>
<% if @minimum_password_length %>
<br>
<em><%= @minimum_password_length %> characters minimum</em>
<% end %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br>
<%= f.password_field :password_confirmation, autocomplete: "new-password" %>
</div>
<div class="actions">
<%= f.submit "Update" %>
</div>
<% end %>
最後に、ヘッダーメニューにパスワード変更ページへのリンクを追加します。
<% if user_signed_in? %>
<li class="nav-item dropdown">
<%= link_to "#", class: "nav-link dropdown-toggle", data: { bs_toggle: "dropdown" }, aria: { expanded: false } do %>
<i class="bi bi-person-circle"></i>
<% end %>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="navbar-dropdown">
<%= link_to "Settings", edit_user_registration_path, class: "dropdown-item" %>
<%= link_to "Password", account_password_path, class: "dropdown-item" %>
<div class="dropdown-divider"></div>
<%= button_to "Logout", destroy_user_session_path, method: :delete, class: "dropdown-item" %>
</div>
</li>
<% else %>
<li class="nav-item"><%= link_to "Sign Up", new_user_registration_path, class: "nav-link" %></li>
<li class="nav-item"><%= link_to "Login", new_user_session_path, class: "nav-link" %></li>
<% end %>
ここまでで、見た目は以下のようになります。
現在のパスワードを入力した後に、新しいパスワードを入力してパスワードが変更されるか確認してみましょう。
また、間違ったパスワードを入力するとエラーが表示されることも確認しましょう。
確認ができれば完了です。
まとめ
Deviseをカスタマイズして、プロフィール更新とパスワード変更ページを作成しました。
- ユーザーは現在のパスワード無しでプロフィール更新ができる
- パスワード変更は専用のページで行う
が実現できたはずです。
Deviseのカスタマイズは少し手間がかかるかもしれませんが、UXを向上させるためには非常に効果的です。
ぜひ試してみてください。
参考までに、今回のコミットログはこちらになります。
スポンサーリンク
コメント
Comments are closed.