大ちゃんの駆け出し技術ブログ

RUNTEQ受講生のかわいいといわれるアウトプットブログ

【Devise】パスワードリセット機能実装手順

はじめに

こんにちは!大ちゃんの駆け出し技術ブログです。

deviseでユーザ登録機能とログイン機能の実装に関する記事はたくさんありますが、deviseでパスワードリセット機能を実装したかったのですが思ったよりも記事の数が少なかったので自分で記事にしてみました。何かのお役に立てればと思います。なお、ログイン機能とユーザ登録機能については既にdeviseで実装済みであることを想定しています。

基本設定

まずはuser.rbrecoverableを追加します。

devise :database_authenticatable, :registerable,
        :recoverable, :rememberable, :validatable, :omniauthable

また、deviseのマイグレーションファイルでrecoverableの箇所をコメントアウトしていた方はコメントアウトを外してuserのカラムに加えてください。

## Recoverable
  t.string   :reset_password_token
  t.datetime :reset_password_sent_at
  t.boolean  :allow_password_change, :default => false

次にパスワードリセットメール送信画面のレイアウトを整えます。自分はtailwindとslimを使っているので以下の部分はtaiwindを使っている方のみコピペしてください。

/ app/views/users/passwords/new.html.slim
.flex.flex-col.items-center.justify-center.h-screen.select-none
  .flex.flex-col.-mt-32.bg-brown-50.px-6.sm:px-6.md:px-8.lg:px-10.py-8.rounded-xl.shadow-2xl.w-full.max-w-md.border-l-4.border-brown-600
    .text-xl.top-sub-title.text-center
      | パスワードリセット
    .mt-10
      = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
        = render "users/shared/error_messages", resource: resource
        .relative.w-full.mb-3
          = f.label :email, class: 'form-label-basic-block'
          = f.email_field :email, autofocus: true, autocomplete: "email", class: "input-form-basic-block"
        .text-center.mt-6
          .actions
            = f.submit "リセットメールを送信", class: "p-3 rounded-lg bg-brown-600 outline-none text-white shadow w-auto justify-center focus:bg-brown-700 hover:bg-brown-500"
            = render  "shared/signup_links"

パスワードリセットを実際に行う画面のレイアウトはリセットトークンがないと遷移できない仕様となっているため見ることはできませんが、レイアウトを整えておきます。

.flex.flex-col.items-center.justify-center.h-screen.select-none
  .flex.flex-col.-mt-32.bg-brown-50.px-6.sm:px-6.md:px-8.lg:px-10.py-8.rounded-xl.shadow-2xl.w-full.max-w-md.border-l-4.border-brown-600
    .text-xl.top-sub-title.text-center
      | パスワード変更
    .mt-10
      = form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
        = render "users/shared/error_messages", resource: resource
        = f.hidden_field :reset_password_token
        .relative.w-full.mb-3
          = f.label :password, class: 'form-label-basic-block'
          - if @minimum_password_length
            em
              | (
              = @minimum_password_length
              |  文字以上で入力してね)
          = f.password_field :password, autofocus: true, autocomplete: "new-password", class: "input-form-basic-block"
        .relative.w-full.mb-3
          = f.label :password_confirmation, class: 'form-label-basic-block'
          = f.password_field :password_confirmation, autofocus: true, autocomplete: "new-password", class: "input-form-basic-block"
        .text-center.mt-6
          .actions
            = f.submit "パスワードをリセット!", class: "p-3 rounded-lg bg-brown-600 outline-none text-white shadow w-auto justify-center focus:bg-brown-700 hover:bg-brown-500"
            = render  "shared/signup_links"

パスワードの変更メールを作成します。edit_user_password_urlで変更画面への遷移をするようにします。reset_password_tokenがないと編集画面に遷移できないため、必ずリンクにreset_password_tokenを含めてください。

p
  = @resource.email
  | 様
p
  | ログインのパスワードリセットの申請を受け付けました。
p
  | パスワードの再設定をご希望の場合は、以下のリンクをクリックし 新しいパスワードをご登録ください。
p
  = link_to 'パスワード変更', edit_user_password_url(@resource, reset_password_token: @token)
p
  | ※パスワードリセットの申請に心当たりがない場合は、以降の対応は不要となります。
p
  | ※リンクの有効期限は24時間です。

ちなみにパスワードリセットのリンクの有効期限はデフォルトで6時間となっていますが、devise.rbで変更可能です。

# Time interval you can reset your password with a reset password key.
# Don't put a too small interval or your users won't have the time to
# change their passwords.
config.reset_password_within = 24.hours

これで基本設定は完了です。

メールアドレスの作成

開発アプリ用のメールアドレスを作成しましょう。基本的には以下の英語文献の記事を参照すれば実装できます。

Getting Devise to send reset password link

gmailのアカウント作成をします。ユーザ名などはお任せします。使用されていないgmailアドレスを登録してください。

https://i.gyazo.com/fc0c429cce1074b69a4e9469485882e2.png

登録後、アカウントの設定でhttps://myaccount.google.com/lesssecureappsにアクセスします。ここで安全性の低いアプリのアクセスを有効にすることで開発環境からのアクセスを許可します。

https://i.gyazo.com/c6e1368eaad7581fe479588ab0ca6efb.png

環境変数を管理するdotenvをインストールします。

gem 'dotenv-rails'

.envファイルを作成し、そこに登録したメールアドレスとパスワードを記載します。

GMAIL_USERNAME = hoge@gmail.com
GMAIL_PASSWORD = hogehogehogehoge

.envファイルはコミットされないようにgitignoreで設定します。

# .gitignore
.env

development.rbで以下の設定を行います。

# config/environments/development.rb
config.action_mailer.default_url_options = {  host: 'localhost', port: 3000 }
  # mail setting
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :address => "smtp.gmail.com",
    :port => 587,
    :user_name => ENV["GMAIL_USERNAME"] ,
    :password => ENV["GMAIL_PASSWORD"] ,
    :authentication => :plain,
    :enable_starttls_auto => true
  }

これによりメールの送信が登録したアドレスで行えるようになりました。

実装確認

まずパスワードリセット画面で開発環境で実際にユーザ登録済みのメールアドレスを入力してください。完了したら送信ボタンを押します。

https://i.gyazo.com/d3b2dcbe49fbcf1e467f0cafe95fe8a0.png

するとターミナル上でメール送信の処理が行われていることがわかります。

Devise::Mailer#reset_password_instructions: processed outbound mail in 19.0ms
Delivered mail 60a598b8236ca_b8513fd849f29f48480ad (3861.7ms)
Date: Thu, 20 May 2021 08:01:12 +0900
From: please-change-me-at-config-initializers-devise@example.com
Reply-To: please-change-me-at-config-initializers-devise@example.com
To: hoge@gmail.com
Message-ID: <60a598b8236ca_b8513fd849f29f48480ad.mail>
Subject: =?UTF-8?Q?=E3=83=91=E3=82=B9=E3=83=AF=E3=83=BC=E3=83=89=E3=81=AE=E5=86=8D=E8=A8=AD=E5=AE=9A=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6?=
Mime-Version: 1.0
Content-Type: text/html;
 charset=UTF-8
Content-Transfer-Encoding: base64

送信したメールアドレスを確認しましょう。実際にメールが届いていることが確認できます。反対に、登録したgmailアドレスの方を確認すると、送信済みボックスに同様のメールが送られていることが確認できます。

https://i.gyazo.com/117597ecfb183f1c437696a6c3dec225.png

パスワードの変更リンクをクリックするとパスワード変更画面に遷移します。

https://i.gyazo.com/992de7bf55adecc2b0a80aeb919ea790.png

ここで新しいパスワードを入力することでパスワードのリセット及びサインインを同時に行ってくれます。deviseのよしなにやってくれている機能は本当にすごいですね!