LoginSignup
16
16

More than 1 year has passed since last update.

deviseによるgmail認証、本番環境への適用

Last updated at Posted at 2021-07-31

概要

本記事では、Ruby on RailsのGem「devise」を用いて、ユーザー新規登録機能を実装していきます。
本番環境でメール認証が適用できない点で詰まったので、本番環境での設定方法まで解説していきます。

本記事でやること

  • Gmail認証を使ったユーザー新規登録方法
  • Gmail側の設定
  • メール内容をカスタマイズ
  • 本番環境でもGmail認証が使えるようにする

環境

  • バックエンド

    • Ruby 2.6.5
    • Rails 6.0.3
  • Gem

    • devise
    • devise-i18n
    • dotenv-rails
  • データベース

    • MySQL 5.7

参考にした記事

【Rails備忘録】deviseまとめ

Deviseでログイン機能を追加・日本語化・Bootstrap4適用まで

deviseを使ったログイン機能を実装する!メール認証機能付き

【Rails】deviseでURL認証付きのメールを送信してみる

完成した後の動作

①ユーザー新規登録画面で、情報を入力
sign_up_page.png

②入力したメールアドレス宛にメールが送信されるフラッシュが表示
sing_up_after.png

③Gmailを確認して、メールが届いていることを確認、メール内リンクをクリック
sign_up_gmail.png

④メール認証が完了し、ログインが可能となる
sign_up_aleady_auth.png

補足
メール内のリンクをクリックしないと本人確認をするフラッシュが表示され、ログインができない仕様
sing_up_authentication.png

アカウント確認メールを再送することも可能(本記事に実装方法記載していません)
sign_up_mail_resend.png

前提

  • RailsのMVCなど基本を理解されていること
  • Railsアプリケーションを新規作成済みであること
  • deviseがインストール済みであること
  • Gmailアカウントを作成済みであること

実装(準備編)

マイグレーションを以下の様な構成にして、マイグレーションを実行してください

補足
- メール認証のみであれば、Confirmableの箇所のみコメントアウトすれば良いが、パスワードリセットやログイン情報保持をする場合は、以下のようにRecoverable、Rememberableの箇所もコメントアウトしてください。

20200627035125_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

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

      ## Rememberable
      t.datetime :remember_created_at

      ## Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      t.string   :unlock_token # Only if unlock strategy is :email or :both
      t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    add_index :users, :unlock_token,         unique: true
  end
end

deviseの機能が使えるようuser.rbに以下を記載

app/models/user.rb
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :validatable,
          :confirmable, :lockable, :timeoutable, :trackable

新規登録時のエラーメッセージなどを日本語化させましょう
以下の様な構成になります

config/locales/devise.views.ja.yml
ja:
  activerecord:
    attributes:
      user:
       ~~省略~~
  devise:
    confirmations:
      confirmed: メールアドレスが確認できました。
      new:
        resend_confirmation_instructions: アカウント確認メール再送
      send_instructions: アカウントの有効化について数分以内にメールでご連絡します。
      send_paranoid_instructions: メールアドレスが登録済みの場合、本人確認用のメールが数分以内に送信されます。
            ~~省略~~
    mailer:
      confirmation_instructions:
        action: メールアドレスの確認
        greeting: "%{recipient}様"
        instruction: 以下のリンクをクリックし、メールアドレスの確認手続を完了させてください。
        subject: "アカウントの有効化のご案内"
             ~~省略~~

    shared:
      links:
        back: 戻る
        didn_t_receive_confirmation_instructions: アカウント確認のメールを受け取っていませんか?
        didn_t_receive_unlock_instructions: アカウントの凍結解除方法のメールを受け取っていませんか?
        forgot_your_password: パスワードを忘れましたか?
        sign_in: ログイン
        sign_in_with_provider: "%{provider}でログイン"
        sign_up: 新規登録
      minimum_password_length: "(6~20桁の半角英数字)"
             ~~省略~~

Gmail側の設定をします。
①Gmailにログインし、2段階認証はオンにしてください
2段階認証.png

②アプリパスワードの生成
Gmail → 設定 → アカウント → セキュリティ → アプリパスワード → パスワードを入力
→ アプリを「その他」に設定し、「現在作成しているアプリケーション名」 → 生成
→ 以下の画面になると思いますので、必ずメモしてください!(アプリパスワードは再生成できません)
アプリパスワード.png

Gmailでメールを受け取れるようにする設定にします(開発環境)

config/enviroments/development.rb
  config.action_mailer.default_url_options = {  host: 'localhost', port: 3000 }
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:"smtp.gmail.com",
    domain: 'gmail.com',
    port:587,
    user_name: Rails.application.credentials.gmail[:user_name],
    password: Rails.application.credentials.gmail[:password],
    authentication: :login
  }

重要
GitHubにuser_nameとpasswordを記載するのは危険なため、credentialで保存してください!
以下のコマンドを実行

terminal
EDITOR=vim rails credentials:edit

INSERTにして、以下を記入したら:wqで抜ける

vim
gmail:
 user_name: Gmailアドレス
 password: 先ほど生成したアプリパスワード

ここまできたら一度Githubにプッシュしましょう

実装(Mailer編)

デフォルトのMailer設定を変更,送信元メールアドレスを変更
以下の様な構成にします。

補足
config.confirm_withinでURLの有効期限が設定できます

config/initializers/devise.rb
Devise.setup do |config|
  config.mailer = 'Users::Mailer'

  config.mailer_sender = '認証メール<〇〇〇〇〇〇@gmail.com>'

  require 'devise/orm/active_record'

  config.reconfirmable = true

  config.expire_all_remember_me_on_sign_out = true

  config.password_length = 6..20

  config.timeout_in = 1.day

  config.confirm_within = 1.days

  config.reset_password_within = 6.hours

  config.scoped_views = true

  config.sign_out_via = :delete
end

Mailer自体をオーバーライド

app/mailers/users/mailer.rb
class Users::Mailer < Devise::Mailer
  helper :application
  include Devise::Controllers::UrlHelpers
  default template_path: 'devise/mailer'

  def confirmation_instructions(record, token, opts={})
    if record.unconfirmed_email != nil
      opts[:subject] = "認証を行ってメールアドレス変更手続きを完了してください"
    else
      opts[:subject] = "認証を行ってユーザ登録を完了してください"
    end
    super
  end
end

実装(MVC作成編)

Viewは以下の様な構成にします。

補足
- if文をフォームの下に設置することにより、バリデーションエラーが以下に表示される様になります。
- cssクラスはご自身で設定されているものに変更してください。

app/views/devise/registrations/new.html.erb
<section class="login">
  <div class="login__imgBx">
    <%= image_tag 'introduction.jpg' %>
  </div>
  <div class="login__contentBx">
    <div class="login__formBx">
      <div class="login__title">新規登録</div>
      <%= form_with model: @user, url: user_registration_path, id: 'new_user', class: 'new_user', local: true do |f| %>

      <div class="login__inputBx">
        <%= f.label :name, {class: 'login__label'} %>
        <%= f.text_field :name, maxlength: '50' %>
        <% if @user.errors.include?(:name) %>
          <p class="login__form-error"><%= @user.errors.full_messages_for(:name).first %>
        <% end %>
      </div>

      <div class="login__inputBx">
        <%= f.label :email, {class: 'login__label'} %>
        <%= f.email_field :email, maxlength: '100 '%>
        <% if @user.errors.include?(:email) %>
          <p class="login__form-error"><%= @user.errors.full_messages_for(:email).first %>
        <% end %>
      </div>

      <div class="login__inputBx">
        <%= f.label :password, {class: 'login__label'} %>
        <%= f.password_field :password,
                              autocomplete: "off",
                              minlength: @minimum_password_length,
                              maxlength: '20'
        %>
        <% if @minimum_password_length %>
          <small class="form-text text-muted"><%= t('devise.shared.minimum_password_length', count: @minimum_password_length) %></small>
        <% end %>

        <% if @user.errors.include?(:password) %>
          <p class="login__form-error"><%= @user.errors.full_messages_for(:password).first %>
        <% end %>
      </div>

      <div class="login__inputBx">
        <%= f.label :password_confirmation, {class: 'login__label'} %>
        <%= f.password_field :password_confirmation,
                              autocomplete: "off",
                              minlength: @minimum_password_length,
                              maxlength: '20'
        %>
        <% if @user.errors.include?(:password_confirmation) %>
          <p class="login__form-error"><%= @user.errors.full_messages_for(:password_confirmation).first %>
        <% end %>
      </div>

      <div class="login__inputBx">
        <%= f.submit "新規登録" %>
      </div>
    <% end %>
    <%= render 'devise/shared/links' %>
    </div>
  </div>
</section>

controllerは以下の様な構成にします。(newとcreateアクションをオーバーライドします。)

app/controllers/users/registrations_controller.rb
# frozen_string_literal: true

class Users::RegistrationsController < Devise::RegistrationsController

  def new
    super
    @user = User.new
  end

  def create
    @user = User.new(user_params)
    if @user.save
      flash[:notice] = "ユーザー認証メールを送信いたしました。認証が完了しましたらログインをお願いいたします。"
      redirect_to new_user_session_path
    else
      flash[:alert] = "ユーザー登録に失敗しました。"
      render action: :new and return
    end
  end

  private
    def user_params
      params.require(:user).permit(:name, :email, :password, :password_confirmation)
    end

メール内容のカスタマイズ
app/views/devise/mailer/confirmation_instructions.html.erb を作成
作成後以下の様な構成にします。

補足
登録済みの方が、再度アカウント確認をした場合を想定して、条件分岐で内容を切り替えています。

app/views/devise/mailer/confirmation_instructions.html.erb
  <div><%= @user.name %>様</div>
  <div>〇〇〇〇〇〇〇をご利用いただきありがとうございます。</div>

  <% if @user.try(:unconfirmed_email?) %>
    <div>以下のリンクからユーザの認証を行ってメールアドレス変更手続きを完了してください。</div>
    <div><%= link_to 'ユーザ認証を実行する', confirmation_url(@user,confirmation_token: @token) %></div>
  <% else %>
    <% if @user.confirmed_at != nil %>
      <div>会員登録が完了済みです。</div>
      <div>下記リンクからログインをお願いいたします。</div>
      <p>http://localhost:3000/</p>
    <% else %>
      <div>以下のリンクからユーザの認証を行ってユーザ登録を完了してください。</div>
      <div><%= link_to 'ユーザ認証を実行する', confirmation_url(@user,confirmation_token: @token) %></div>
      <div> このURLの有効期限は24時間です。</div>
    <% end %>
  <% end %>

ここで開発環境でGmailに認証メールが届くか確認しましょう。
確認できたらGithubにプッシュしましょう

実装(本番環境編)

production.rbに認証メール送信で必要なことがあります。
以下の様な構成になります。

補足
ドメイン名を設定してあげないと、本番環境ではGmailに認証メールが届かないため設定しましょう。
環境変数でGmailアドレスやアプリパスワードを渡す必要があるため、dotenv-rails Gemをインストールし、環境変数を.envファイルに記載しましょう

config/environments/production.rb
Rails.application.configure do
  ~~省略~~

  config.action_mailer.perform_caching = false

  config.action_mailer.default_url_options = { host: 'アプリケーションのドメイン名'}

  config.action_mailer.perform_deliveries = true

  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:"smtp.gmail.com",
    domain: 'gmail.com',
    port:587,
    user_name: ENV['SEND_MAIL'],
    password: ENV['GMAIL_SPECIFIC_PASSWORD'],
    authentication: :login,
    openssl_verify_mode: 'none',
    enable_starttls_auto: true
  }

  config.action_mailer.perform_caching = false

  config.action_mailer.raise_delivery_errors = true

  ~~省略~~

end

環境変数の設定は以下の様になります。

.env
SEND_MAIL="Gmailアドレス"
GMAIL_SPECIFIC_PASSWORD="生成したアプリパスワード"

環境変数はGithubにあげるのは危険なため、.gitignoreファイルに.envを追加しましょう

.gitignore
 ~~省略~~
.env

Githubにプッシュしします
これで、本番環境でメール認証が飛んでいるはずです。

苦労した点

Gmailアドレスとアプリパスワードの設定することに気づかず、詰まりました。

本番環境でメールが飛ばない事態が発生しており、本番環境用のMailer設定については記事が少なく大変でしたが、設定できました。

まとめ

deviseはブラックボックスなところが多く、大変ですが、Qiitaを参考に実際に手を動かして、試行錯誤すると、便利な部分はデフォルトでカスタマイズしたいところはカスタマイズできるのでこちらの記事を参考に皆さんのポートフォリオ作りの糧になればと思います。

ご質問などがありましたらコメントいただけると幸いです。

16
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
16