どうもどハマりエンジニアです。
本日はパスワードのリセット機能について実装していきます。
使う概念
- soceryのreset_passwordモジュール
- letter_opener_web
- config
sorceryのreset_passwowrdモジュールをインストールする
$rails g sorcery:install reset_password --only-submodules
def change
add_column :users, :reset_password_token, :string, default: nil
add_column :users, :reset_password_token_expires_at, :datetime, default: nil
add_column :users, :reset_password_email_sent_at, :datetime, default: nil
add_column :users, :access_count_to_reset_password_page, :integer, default: 0
add_index :users, :reset_password_token
end
end
そうすると上記のmigrationが作成されます。
rails db:migrate 実行
Mailerの作成
$rails g mailer UserMailer reset_password_email
(user_mailer.rb)
class UserMailer < ApplicationMailer
def reset_password_email(user)
@user = User.find(user.id)
@url = edit_password_reset_url(@user.reset_password_token)
mail(to: user.email, subject: 'パスワードリセット')
end
end
- default from: 'from@example.com'でメールの送信元のアドレスを指定できる
- mail(to: user.email,subject: 'パスワードリセット')でメールの宛先、件名を指定
(sorcery.rb)
Rails.application.config.sorcery.submodules = [:reset_password]
Rails.application.config.sorcery.configure do |config|
config.user_config do |user|
user.reset_password_mailer = UserMailer
end
config.user_class = 'User'
end
sorcery.rbにreset_passwordサブモジュールを追加し、パスワードリセットに使用するActionMailerとしてUserMailerを定義
コントローラー・ビューの作成
$rails g controller password_resets
(password_resets_controller.rb)
class PasswordResetsController < ApplicationController
skip_before_action :require_login
def new; end
def create
@user = User.find_by(email: params[:email])
if @user
@user.deliver_reset_password_instructions!
redirect_to login_path, success: 'パスワードリセット手順を送信しました'
else
render 'new'
end
end
def edit
@token = params[:id]
@user = User.load_from_reset_password_token(params[:id])
not_authenticated if @user.blank?
end
def update
@token = params[:id]
@user = User.load_from_reset_password_token(@token)
return not_authenticated if @user.blank?
@user.password_confirmation = params[:user][:password_confirmation]
if @user.change_password!(params[:user][:password])
redirect_to login_path, success: 'パスワードを変更しました'
else
flash.now[:danger] = 'パスワードの変更に失敗しました'
render :edit
end
end
end
create()では送信されてきたメールに対応するUserを検索し、「deliver_reset_password_instructions!」を呼び出すことでトークンの発行とメール送信を行っています。
edit()はトークンの存在チェックです。
update()では「change_password!」を呼び出してパスワードの変更を行っています。APIであるため、それぞれのアクションではHTTPステータスコードを状態に応じて返しています。
(routes.rb) ルーティングの設定
resources :password_resets, only: %i[new create edit update]
(new.html.erb)リセット申請画面
<%= form_with url: password_resets_path, local: true, method: :post do |f| %>
<div class="field">
<%= f.label :email, t(User.human_attribute_name(:email)) %><br />
<%= f.text_field :email, class: 'form-control' %>
<%= f.submit '送信', class:'btn btn-primary' %>
</div>
<% end %>
(edit.html.erb)リセット編集画面
<%= form_with model: @user, url: password_reset_path(@token), method: :patch, local: true do |f| %>
<div class="field">
<%= f.label :email %>
<%= @user.email %>
</div>
<div class="field">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="field">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div class="actions">
<%= f.submit '更新する', class: 'btn btn-primary' %>
</div>
<% end %>
メール文作成
(reset_password_email.html.erb)
<h1>パスワードリセット</h1>
<p>
<%= @user.decorate.full_name %>様
パスワード再発行のご依頼を受け付けました。
こちらのリンクからパスワードの再発行を行ってください。
<%= @url %>
</p>
@urlは先ほどmailer.rbで作成
(reset_password_email.text.erb)
<%= @user.decorate.full_name %>様
パスワード再発行のご依頼を受け付けました。
こちらのリンクからパスワードの再発行を行ってください。
<%= @url %>
letter_opener_webを追加し、開発環境では実際のメールは送られないように設定
下記のgemをインストールする
'letter_opener_web'
(routes.rb)設定を加える
mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
configのgemを追加
rails g config:install
config/settings.yml
config/settings.local.yml
config/settings/development.yml
config/settings/production.yml
config/settings/test.yml
上記のファイルが作成されるので、各ファイルに必要な記述をしていきます。
(config/environments/development.rb)
config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = { host: Settings.host }
config.action_mailer.delivery_method = :letter_opener_web
(settings/development.yml)
上記でパスワードリセットの実装は完了です。
実際にパスワードのリセットを申請すると、http://localhost:3000/letter_opener にメールが届くので確認してください。
以上で本日の実装は終了です。