パスワードリセット機能の実装(sorcery)・letter_opener_webで、開発環境では実際にメール送らないように設定

パスワードリセット機能の実装(sorcery)

  1. モジュールをインストール
$ rails g sorcery:install reset_password --only-submodules


2. 自動生成されたマイグレーションファイルをDBに反映

rails db:migrate


3. reset_password_tokenカラムに制約をかける。(app/models/user.rb)

validates :reset_password_token, uniqueness: true, allow_nil: true

※ パスワードが変更される際、reset_password_tokenは削除されnilになるため、allow_nil: trueがないとユニーク制約にに引っかかってしまう。

4. メイラーの作成

$ rails g mailer UserMailer reset_password_email


5. 1 で生成されたconfig/initializers/sorcery.rbで、パスワードリセット用のメイラーにUserMailerを指定

Rails.application.config.sorcery.configure do |config|
  config.user_config do |user|
    user.reset_password_mailer = UserMailer
  end
end


6. reset_password_emailメソッドを記載(app/mailers/user_mailer.rb)

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


7. メイラーviewを設定
(app/views/user_mailer/reset_password_email.html.erb)

<p><%= @user.decorate.full_name %>様</p>
<p>===============================================</p>
 
<p>パスワード再発行のご依頼を受け付けました。</p>
 
<p>こちらのリンクからパスワードの再発行を行ってください。</p>
<p><a href="<%= @url %>"><%= @url %></a></p>

(app/views/user_mailer/reset_password_email.text.erb)

<%= @user.decorate.full_name %>様
===========================================

パスワード再発行のご依頼を受け付けました。

こちらのリンクからパスワードの再発行を行ってください。
<%= @url %>


8. ルーティングを設定

resources :password_resets, only: %i[new create edit update]


9. パスワードリセット申請フォームの作成 (app/views/password_resets/new.html.erb)

<%= form_with url: password_resets_path, local: true do |f| %>

  <%= f.label :email %>
  <%= f.email_field :email %>
  <%= f.submit '送信' %>

<% end %>


10. パスワードリセットフォームの作成 (app/views/password_resets/edit.html.erb)

<%= form_with model: @user, url: password_reset_path(@token), local: true do |f| %>
  <%= render 'shared/error_messages', object: f.object %>
        
    <%= f.label :email %><br>
    <%= @user.email %>
        
    <%= f.label :password %><br>
    <%= f.password_field :password %>
        
    <%= f.label :password_confirmation %><br>
    <%= f.password_field :password_confirmation %>
        
    <%= f.submit '更新' %>
<% end %>


11. コントローラーの設定

class PasswordResetsController < ApplicationController
  skip_before_action :require_login
 
  def new; end
 
  def create
    @user = User.find_by(email: params[:email])
    # DBにデータがあればreset_password_emailメソッド発動。(メールは有効期限付き)
    @user&.deliver_reset_password_instructions!
    #「存在しないメールアドレスです」という旨の文言を表示すると、逆に存在する
    # メールアドレスを特定されてしまうため、DB内にデータがあるかないかに関わらず
    # 成功時のメッセージを送信。
    redirect_to login_path, success: t('.success')
  end
 
  def edit
    @token = params[:id]
    # リクエストで送信されてきたトークンにマッチするデータがあり
 # 有効期限内であれば@userにデータを代入。
    @user = User.load_from_reset_password_token(@token)
 #@userがnilかblankであればnot_authenticatedメソッドを返す。
    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



letter_opener_webで、開発環境では実際に
メール送らないように設定

  1. gemをインストール
gem 'letter_opener_web
$ bundle install


2. config/routes.rbに以下を記載

mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?


3. config/environments/development.rbに以下を記載

config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.action_mailer.delivery_method = :letter_opener_web



環境ごとに異なる定数を管理

configというgemを使うことで環境ごとの定数をすっきり管理することができ、メンテナンスも楽になる。

gemのインストール

gem 'config'
bundle install


設定ファイルの生成

$ rails g config:install

config/settings.yml:環境ごとに値が変わらない設置値を記載
config/settings/development.yml:開発環境のみで使用する値を記載
config/settings/production.yml:本番環境のみで使用する値を記載
config/settings/test.yml:テスト環境のみで使用する値を記載

(例)

# config/settings/development.yml

host: 'localhost:3000'
#config/environments/development.rb

config.action_mailer.default_url_options = { host: Settings.host }
config.action_mailer.delivery_method = :letter_opener_web