Railsにdeviseでメール認証を使ったパスワード再設定を実装する

前回の記事ではRailsアプリにdeviseを使ってユーザーページを追加しました。 今回はdeviseが用意してくれているrecoverble モジュールを使ってメール認証を使ったパスワード再設定機能を追加します。

実装対象のアプリはdeviseを使ってログイン機能を実装する記事で使用したアプリです。

実装は次の手順で行います。

  1. recoverbleモジュールの有効化を確認
  2. Gmailのアプリパスワードを発行
  3. dotenv gemを使用してメールアドレスとアプリパスワードを環境変数
  4. メール送信用サーバをGmail用に設定
  5. 送信元のメールアドレス設定

1. recoverbleモジュールの有効化を確認

devise gemのセットアップ時にrecoverble モジュールはデフォルトで有効化されています。 認証機能を追加したモデルを確認することでモジュールの追加を確認できます。

# app/models/user.rb
class User < ApplicationRecord
  ...
  # ↓recorvebleモジュールが有効になっている
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
end

また、deviseセットアップ時のマイグレーションファイルにもrecorveble モジュールが有効化されているか確認します。

# db/migrate/xxx_devise_create_user.rb

...
class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      ...

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ...
    end

    ...
    add_index :users, :reset_password_token, unique: true
    ...
  end
end

2. Gmailのアプリパスワードを発行

下記記事を参考にしてアプリパスワードを発行します。

[*Rails*] deviseの使い方(rails6版) - Qiita

発行したアプリパスワードを後述するdotenv gemで使用する.env ファイルに追加します。

3. dotenv gemを使用してメールアドレスとアプリパスワードを環境変数

メールサーバの送信設定に使用する環境変数dotenv gemで読み込む.env ファイルに追加します。

dotenv gemの使い方 - karlley's tech blog

# .env

GOOGLE_MAIL_ADDRESS = '使用するGmailのアドレス'
GOOGLE_APP_PASSWORD = 'アプリパスワード'

4. メール送信用サーバをGmail用に設定

dotenv gemを使用して作成した環境変数でメールアドレスやパスワードでメール送信用サーバをGmail用に設定します。

メール送信機能はRailsで用意されているAction Mailerを使用します。 config/environments/development.rbGmail用にメール送信用サーバの設定を追加します。

初期状態ではdefault_url_options のみ下記のようにデフォルトで設定されています。

# config/environments/development.rb

require 'active_support/core_ext/integer/time'

Rails.application.configure do
  ...
  # デフォルトで設定されている
  # Default url for mailer
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

ちなみに、devise gemセットアップ時にメール送信用サーバの設定を促されますがメール送信機能を使いたい時に設定すれば大丈夫です。

# devise gemセットアップに表示される

$ rails generate devise:install
...
===============================================================================

Depending on your application's configuration some manual setup may be required:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

     * Required for all applications. *
     ...
===============================================================================

下記にようにGmailに合わせたAction Mailerの設定を追加します。

require 'active_support/core_ext/integer/time'

Rails.application.configure do
  ...
  # Default url for mailer
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
  # メール送信失敗時のエラーを発生させる
  config.action_mailer.raise_delivery_errors = true
  # メール送信にSMTPを使用する
  config.action_mailer.delivery_method = :smtp
  # SMPTの詳細設定
  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    port: 587,
    # HELOコマンドで使用するドメイン、たぶん無くてもok
    domain: 'smtp.gmail.com',
    # Gmailのメールアドレス
    user_name: ENV['GOOGLE_MAIL_ADDRESS'],
    # Googleのアプリパスワード
    password: ENV['GOOGLE_APP_PASSWORD'],
    # メールサーバーの認証の種類
    authentication: 'plain',
    # STARTTLSを自動検出して有効化
    enable_starttls_auto: true
  }
end

ENV[] はdotenv gemで設定した環境変数が展開されます。 Action Mailerの設定はRailsガイドと下記のリンクを参考にしました。

Action Mailer の基礎 - Railsガイド

5. 送信元のメールアドレス設定

メールのfrom欄に表示される送信元のメールアドレスをconfig/initializes/devise.rb に設定します。 ちなみに変更しなくても動作するのを確認したのでデフォルトのままでもokだと思います。 コードレビュー時に以下のアドバイスもらいました。

ここはdeviseが送信するメールのfromに当たる部分なので、 no-reply@example.com のようなそれらしいアドレスにしておくと良いですね。

アドバイス通りにno-reply@example.com に変更します。

# config/initializes/devise.rb

Devise.setup do |config|
  ...
  # 変更前
  config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'

  # 変更後
  config.mailer_sender = 'no-reply@gmail.com'

以上でdeviseでメール認証を使ったパスワード再設定を実装は完了です。 /users/sign_in にアクセスし、Forgot your password? をクリックすると送信先のメールアドレスの入力を求められるので入力後、送信するとパスワード再設定用のメールが届くようになります。

追記

自前で用意したGmailを使ってメール送信の動作確認を行いましたがletter_opener_webというgemを使った方が実践的だということ教えてもらったので別記事にまとめました。

letter opener webでRailsのメール送信を確認する - karlley's tech blog

Gmailでの設定が面倒くさいという方はこちらを試してみると良いかもしれません。

まとめ

メール送信機能の公式ドキュメントが見つからず時間が掛かってしまいました。 メール送信機能はdeviseが用意してい機能ではなくRailsの機能だと理解していないことが原因でした。 gemの使い方にはまだまだ慣れが必要だと感じますが、少しずつ実装できているのでもっとたくさん触れて覚えていこうと思います。

参照

Railsにdeviseを使ってログイン機能を実装する - karlley's tech blog

[*Rails*] deviseの使い方(rails6版) - Qiita

dotenv gemの使い方 - karlley's tech blog

why is authentication: 'plain' the default setting for actionmailer in rails (with gmail smtp)? - Stack Overflow

STARTTLSとは - 意味をわかりやすく - IT用語辞典 e-Words

ASCII.jp:メールを送る際に使われるSMTPの仕組みとは?

Action Mailer の基礎 - Railsガイド