6
0

More than 3 years have passed since last update.

【第11章】Railsチュートリアル 5.1(第4版) アカウントの有効化

Last updated at Posted at 2020-01-30

はじめに

個人的な理解・備忘録を目的としてます。
筆者自身は動画版Railsチュートリアルで進めているため、アプリ作成中コード・ブランチ名などの若干の違いがありますので参考程度に流し見して頂けたら嬉しいです。
理解不足のため、何かありましたらコメント等ご指摘してくださると幸いです(^_^;)

11.0 本章の目標

本章では、アカウントを有効化するステップを新規登録の途中に差し込むことで、本当にそのメールアドレスの持ち主なのかどうかを確認できるようにする。(仮に誰かがミスって登録しても大丈夫なように)

例.ECサイト登録した場合のユーザー(ユ)とサーバー(サ)のやりとり
1. (ユ)→(サ) 「このemailで登録で」
2. (サ)→(ユ) 「メール送ったから確認して」
3. (ユ)→(サ) 「来たメールのURLクリックしたよ」
4. 【NG】(サ)→(ユ) 「違うからもう一回だね」
4. 【OK】(サ)→(ユ) 「登録するね(DB書き込みするか)」

<実装内容>
(1) 有効化トークンやダイジェストを関連付けておいた状態に
(2) 有効化トークンを含めたリンクをユーザーにメールで送信
(3) ユーザーがそのリンクをクリックすると有効化

また、ユーザーがパスワードを忘れたときにパスワードを再設定できるようにする。

アカウント有効化の段取りは以下の手順(第9章のユーザーの登録に近い)
1. ユーザーの初期デフォルトの状態は「有効化されていない」(unactivated) にしておく
2. ユーザー登録(Signup)が行われたときに、有効化トークンと、それに対応する有効化ダイジェストを生成する
3. 有効化ダイジェストはDBに保存しておき、Signupしたユーザーには(有効化トークンをリンクに仕込んで)メールアドレスにメールを送信
4. ユーザーがメールのリンクをクリックしたら(本人だったら)、アプリケーションはメールアドレスをキーにしてDBでユーザーを探し、DB内に保存しておいた有効化ダイジェストと比較してトークンを認証する
5. ユーザーを認証できたら、ユーザーのステータスを「有効化されていない」から「有効化済み」(activated) に変更する
(認証できなければhomeを表示)

検索キー string digest authentication
email password password_digest authenticate(password)
id remember_token remember_digest authenticated?(:remember, token)
email activation_token activation_digest authenticated?(:activation, token)
email reset_token reset_digest authenticated?(:reset, token)

公式より参考)

機能としては10章の時点で基本的な機能実装は完成している。
本章(第11章)+第12章では応用的な部分の実装になる。

11.1 AccountActivationsリソース

まずはGitで新機能用のトピックブランチを作成

$ git checkout -b account-activation

 
ユーザーを有効にしたときの変更後のデータモデル
image.png
公式より参考)

今回使うのは赤点線部分で、
activation_digest → 有効化トークンと一致させるもの
activated      → 有効化されてるか否かを真偽値(1 or 0)で、デフォでは偽(0)、「if user.activated?」などで使う
activated_at    → いつ有効化されたか(有効化の機構でなくログとして残す程度)

11.1.1 AccountActivationsコントローラ

AccountActivationsリソースを作るために、AccountActivationsコントローラを生成する

$ rails generate controller AccountActivations

ルーティングにアカウント有効化用のリソース resources行(editアクション)を追加

config/routes.rb

resources :users
resources :account_activations, only: [:edit] 
# (ユーザから) GET /account_activations/:id/edit
# params[:id] <== 有効化トークン入れる
# Controller: params[:id]

11.1.2 AccountActivationのデータモデル

マイグレーションをコマンドラインで実行して先のデータモデル3つを追加すると、3つの属性が新しく追加される

$ rails generate migration add_activation_to_users activation_digest:string activated:boolean activated_at:datetime

同じ内容の2行版(>はシェル側の挿入で入力しない。上の連続が安定かも)
$ rails generate migration add_activation_to_users \
> activation_digest:string activated:boolean activated_at:datetime

Running via Spring preloader in process 23013
      invoke  active_record
      create    db/migrate/[timestamp ex. 2020...]_add_activation_to_users.rb

 
アカウント有効化用の属性とインデックスを追加するマイグレーション。デフォルト:falseを追加

db/migrate/[timestamp]_add_activation_to_users.rb

class AddActivationToUsers < ActiveRecord::Migration[5.1]
  def change
    add_column :users, :activation_digest, :string
    add_column :users, :activated, :boolean, default: false
    add_column :users, :activated_at, :datetime
  end
end

マイグレーションを実行

$ rails db:migrate

Userモデルにアカウント有効化のコードを追加する

app/models/user.rb

class User < ApplicationRecord
  attr_accessor :remember_token, :activation_token
  before_save   :downcase_email
  before_create :create_activation_digest


# メールアドレスをすべて小文字にする
  def downcase_email
    self.email = self.email.downcase
  end

  # 有効化トークンとダイジェストを作成および代入する
  def create_activation_digest
    self.activation_token  = User.new_token
    self.activation_digest = User.digest(activation_token)
  # @user.activation_digest => ハッシュ値が入る
  end

サンプルユーザーの生成とテストのため、テスト時のサンプルとユーザーを事前に有効化する。なお、Time.zone.nowはRailsの組み込みヘルパー(特に .zone)であり、サーバーのタイムゾーンに応じたタイムスタンプを返す。

$ ruby -e "puts Time.now"
2020-01-22 02:34:53 +0000

サンプルユーザーを最初から有効に

db/seeds.rb

User.create!(name:  "Example User",
             email: "example@railstutorial.org",
             password:              "foobar",
             password_confirmation: "foobar",
             admin:     true,
             activated: true,
             activated_at: Time.zone.now)

99.times do |n|
  name  = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  password = "password"
  User.create!(name:  name,
              email: email,
              password:              password,
              password_confirmation: password,
              activated: true,
              activated_at: Time.zone.now)
end

fixtureのユーザーも有効(activated: true)、タイムスタンプの追加

test/fixtures/users.yml

michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>
  admin: true
  activated: true
  activated_at: <%= Time.zone.now %>

archer:
  name: Sterling Archer
  email: duchess@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

lana:
  name: Lana Kane
  email: hands@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

malory:
  name: Malory Archer
  email: boss@example.gov
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>

<% 30.times do |n| %>
user_<%= n %>:
  name:  <%= "User #{n}" %>
  email: <%= "user-#{n}@example.com" %>
  password_digest: <%= User.digest('password') %>
  activated: true
  activated_at: <%= Time.zone.now %>
<% end %>

DBを初期化&サンプルデータを再度生成し直し、変更を反映

$ rails db:migrate:reset
$ rails db:seed

ここまでで、有効化トークンをダイジェスト(ハッシュ値)にして、DBに保存する流れを実装できた。

11.2 アカウント有効化のメール送信

データのモデル化が終わったので、今度はアカウント有効化メールの送信に必要なコードを追加する。ここではAction Mailerライブラリを使ってUserのメイラーを追加していく。
これはUsersコントローラのcreateアクションで有効化リンクをメール送信するために用いるもので、構成がコントローラのアクションとよく似ているため、メールのテンプレートをビューと同じように定義できる。このテンプレートの中に有効化トークンとメールアドレス (= 有効にするアカウントのアドレス) のリンクを含める。

11.2.1 送信メールのテンプレート

メイラーは、モデルやコントローラと同様にrails generateで生成できる。

$ rails generate mailer UserMailer account_activation password_reset

※補足
rails generate 
mailer(単数:controller等) 
UserMailer(その名前つける) 
account_activation password_reset (メソッド2つ)

生成されたUserメイラー

app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer

  def account_activation
    @greeting = "Hi"
    mail to: "to@example.org" #=> return mail boject

  end

  def password_reset
    @greeting = "Hi"

    mail to: "to@example.org"
  end
end

コントローラーのアクションっぽいが、メソッドと呼ぶ方がいい(らしい)。
読み込んだテキストがそれぞれビューとして呼び出される。
 

アカウント有効化メイラーのテキストビュー (自動生成)
app/views/user_mailer/account_activation.text.erb



User#account_activation

<%= @greeting %>, find me in app/views/user_mailer/account_activation.text.erb

account_activationメソッドの@greetingの文面「Hi!」が送り付けられる。
 

アカウント有効化メイラーのHTMLビュー (自動生成)
app/views/user_mailer/account_activation.html.erb


<h1>User#account_activation</h1>

<p>
  <%= @greeting %>, find me in app/views/user_mailer/account_activation.html.erb
</p>

生成されたApplicationメイラー

app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: "from@example.com"
  layout 'mailer'
end

MVCのモデル的な解釈としてActionメイラーは、
Mail(文面) → View
Mailer    → controller
のような位置付けになっている。
(コンソールでメイラーの親クラスを追うとコントローラーに繋がる)

生成されたApplicationメイラー

app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end

fromアドレスのデフォルト値を更新したアプリケーションメイラー

app/mailers/application_mailer.rb

class ApplicationMailer < ActionMailer::Base
  default from: "noreply@example.com"
  layout 'mailer'
end

 
アカウント有効化リンクをメール送信する

app/mailers/user_mailer.rb

class UserMailer < ApplicationMailer

  def account_activation
    @greeting = "Hi"
    # (旧) mail to: "to@example.org" #=> return mail boject
    #=> app/views/user_mailer/account_activation.text.erb
    #=> app/views/user_mailer/account_activation.html.erb

    mail to: @user.email #=> mail object

    # https://hogehoge.com/account_activation/:id/edit
    # :id <= @user.activation_tokenを入れる

  end

  # def account_activation(user)
  #   @user = user
  #   mail to: user.email, subject: "Account activation"
  # end

  def password_reset
    @greeting = "Hi"
    mail to: "to@example.org"
  end
end

メールのテンプレートを実際に有効化メール(返信用)

作りたいメールアドレスはこれ

account_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.com

q5lt38hQDc_959PVoo6b7Aはnew_tokenメソッドで生成されたもので、URLで使えるようにBase64でエンコードされている。

エンコード

エンコードとは、「URL(ホームページの住所)で使えない文字を別の表現(形式)に置き換えること」。チュートリアルではBase64(64進数、すべてのデータをアルファベット(a~z, A~z)と数字(0~9)、一部の記号(+,/)の64文字)のエンコード形式で行う。エンコードしたデータを元の形に戻す行為は「デコード」と呼ぶ。

 あ     → エンコード → %E3%81%82
%E3%81%82 → デコード  → あ

<参考>
エンコード (encode)
URLエンコード・デコード
base64ってなんぞ??理解のために実装してみた

気をつけるべきは、メールのURLが@でなく%40担っていること。これは、「エスケープ」と呼ばれる手法で、通常URLでは扱えない文字を扱えるようにするために変換されている。

このメールによってRailsサーバーで行いたいのは以下の処理。


①ユーザーをメールアドレス(finde_byで@user.email)で検索
②有効化トークンを認証(authenticated?で@user.activation_token)


  
アカウント有効化のテキストビュー
app/views/user_mailer/account_activation.text.erb


Hi <%= @user.name %>,

Welcome to the Sample App! Click on the link below to activate your account:

<%= edit_account_activation_url(@user.activation_token, email: @user.email) %>

アカウント有効化のHTMLビュー
app/views/user_mailer/account_activation.html.erb


<h1>Sample App</h1>

<p>Hi <%= @user.name %>,</p>

<p>
Welcome to the Sample App! Click on the link below to activate your account:
</p>

<%= link_to "Activate", edit_account_activation_url(@user.activation_token,
                                                    email: @user.email) %>

ちなみに、コンソールを開いてCGIモジュールのescapeメソッドでメールアドレスや"Don't panic!"の文字列を確認すると、以下のようにエスケープできている。

CGI.escape('foo@example.com')
 => "foo%40example.com" 
2.6.3 :002 > CGI.escape("Don't panic!")
 => "Don%27t+panic%21" 

11.2.2 送信メールのプレビュー

テンプレートの実際の表示を簡単に確認するために、メールプレビューという手法を使う。Railsでは、特殊なURLにアクセスするとメールのメッセージをその場でプレビューすることができるので、メールを実際に送信しなくてもok。
これを利用するためには、アプリケーションのdevelopment環境の設定を変更する。筆者の環境ではクラウドIDEのため下記、ローカルならlocalhost:3000

config/environments/development.rb

# Don't care if the mailer can't send.
  config.action_mailer.raise_delivery_errors = true #=> デフォfalseから変更
  config.action_mailer.delivery_method = :test #=> rails場でメールをログとして出す(実際には送らない)
  host = '******.vfs.cloud9.ap-northeast-1.amazonaws.com/' # sample_app(preview)のドメイン,https://の後
  config.action_mailer.default_url_options = { host: host, protocol: 'https' }

Userメイラープレビュー アカウント有効化のプレビューメソッド

test/mailers/previews/user_mailer_preview.rb

 # Preview this email at
 # http://localhost:3000/rails/mailers/user_mailer/account_activation
  def account_activation
    user = User.first
    user.activation_token = User.new_token
    UserMailer.account_activation(user) #=> mail object
  end

先ほどのリンクにメイラーを付け足してプレビューで検索確認。指定のURLでアカウント有効化メールをプレビューできるようになった。(サーバーは再起動)

******.vfs.cloud9.ap-northeast-1.amazonaws.com/rails/mailers/user_mailer/account_activation

メール

image.png

Accountをクリック

image.png


先ほどのtext(メール添付SS下部リンクは省略)。
account_activations/******(平文)/edit?email=example%40railstutorial.org

スクリーンショット 2020-01-28 18.33.51.png


11.2.3 送信メールのテスト

Railsによって自動生成されているテスト例を使い、メールプレビューのテストも作成してプレビューをダブルチェックする。

test/mailers/user_mailer_test.rb

require 'test_helper'

class UserMailerTest < ActionMailer::TestCase

  test "account_activation" do
    user = users(:michael)
    user.activation_token = User.new_token
    mail = UserMailer.account_activation(user)
    assert_equal "Account activation", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@example.com"], mail.from
    assert_match user.name,               mail.body.encoded
    assert_match user.activation_token,   mail.body.encoded
    assert_match CGI.escape(user.email),  mail.body.encoded
  end
end

テストファイル内のドメイン名を正しく設定するため、テストのドメインホストを設定する。

config/environments/test.rb

config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { host: 'example.com' }

これでテストし、通過。
※ メーラーは書き方が少し異なる。


$ rails test:mailers

11.2.4 ユーザーのcreateアクションを更新

ユーザー登録にアカウント有効化を追加する。あとはユーザー登録を行うcreateアクションに数行追加するだけで、メイラーをアプリケーションで実際に使えるようになる。
前回はユーザーのプロフィールページにリダイレクトしていたが、アカウント有効化を実装するうえでは無意味な動作のため、リダイレクト先をルートURLに変更する。
 
ユーザー登録にアカウント有効化を追加する。

app/controllers/users_controller.rb

def create
    @user = User.new(user_params)
    if @user.save
      UserMailer.account_activation(@user).deliver_now
      flash[:info] = "Please check your email to activate your account."
      redirect_to root_url

アカウント作成 → ログインすると、サーバー(ターミナル)でメールの文面が確認できる。
これが、11.2.3であった:testのもの。

config.action_mailer.delivery_method = :test

スクリーンショット 2020-01-29 1.40.34.png

ただしテストでは、singnupで引っ掛かりが起きる。これはリダイレクト先をプロフィールページからルートURLに変更し、かつユーザーは以前のようにログインしないようにしているため(機能的に問題なくてもNG)。

失敗するテストを一時的にコメントアウトする

test/integration/users_signup_test.rb

# assert_template 'users/show'
# assert is_logged_in?

11.3 アカウントを有効化する

ここからは先ほどのやりとりのうち、下記を実装。
3. (ユ)→(サ) 「来たメールのURLクリックしたよ」
4. 【NG】(サ)→(ユ) 「違うからもう一回だね」
4. 【OK】(サ)→(ユ) 「登録するね(DB書き込みするか)」

11.3.1 authenticated?メソッドの抽象化

authenticated?メソッドは現在、remember_digestの記憶トークン対応のみのため、これでは今回実装したい有効化トークンも含めて2つ書く手間でDRYとはいえない。
そのため、今回はsendメソッドを使い動的ディスパッチ(メソッドの実行直前に実行するメソッドを呼び出すこと)として抽象化する。

これだけだとよくわからないのでコンソールを開く。

2.6.3 :001 > a = "hogehoge"
 => "hogehoge" 
2.6.3 :002 > a.send("length")
 => 8 
2.6.3 :003 > a.length
 => 8 

sendはメソッド名を文字列にできる(文字列なので式展開ができる)。つまり

hensuu = "activation"
.send("#{hensuu}_digest") #=> akj3a3%4au#(前回)
hensuu = "remember"
.send("#{hensuu}_digest") #=> nil(今回 まだない)

のような切り替えができる。
シンボル表記(:activation)でもok

抽象化されたauthenticated?メソッド。引数を追加したり

app/models/user.rb

# トークンがダイジェストと一致したらtrueを返す
  def authenticated?(attribute, token)
    digest = send("#{attribute}_digest")
    return false if digest.nil?
    BCrypt::Password.new(digest).is_password?(token)
  end

このままではREDのため、
sessions_helperのcurrent_user内でauthenticated?メソッドを抽象化

app/helpers/sessions_helper.rb
# 現在ログイン中のユーザーを返す (いる場合)
  def current_user
    if (user_id = session[:user_id])
      @current_user ||= User.find_by(id: user_id)
    elsif (user_id = cookies.signed[:user_id]) #=> signedで復号化
      user = User.find_by(id: user_id)
      #旧(引数不足) if user && user.authenticated?(cookies[:remember_token])
      if user && user.authenticated?(:remember, cookies[:remember_token])

Userテストでも

test/models/user_test.rb

test "authenticated? should return false for a user with nil digest" do
    assert_not @user.authenticated?(:remember, '')
  end

これでテストは通過

11.3.2 editアクションで有効化

editアクションの実装。paramsハッシュで渡されたメールアドレスに対応するユーザーを認証(有効かどうか?)。

app/controllers/account_activations_controller.rb

class AccountActivationsController < ApplicationController
  def edit
    user = User.find_by(email: params[:email])
    if user && !user.activated? && user.authenticated?(:activation, params[:id])
      #Success => Signup
      user.update_attribute(:activated,    true)
      user.update_attribute(:activated_at, Time.zone.now)
      log_in user
      flash[:success] = "Account activated!"
      redirect_to user
    else
      #Failure
      flash[:danger] = "Invalid activation link"
      redirect_to root_url
    end
  end
end

ユーザーの有効化が役に立つためには、ユーザーが有効である場合にのみログインできるようにログイン方法を変更する必要がある。
そのためには、user.activated?がtrueの場合にのみログインを許可し、そうでない場合はルートURLにリダイレクトしてwarningで警告を表示する。

app/controllers/sessions_controller.rb

def create
    user = User.find_by(email:params[:session][:email])
   if user && user.authenticate(params[:session][:password])
      if user.activated? #=>上かつアクティベーションしてるか?
        log_in user
        params[:session][:remember_me] == '1' ? remember(user) : forget(user)
        redirect_back_or user
      else #=> してなかったら
        message  = "Account not activated. "
        message += "Check your email for the activation link."
        flash[:warning] = message
        redirect_to root_url
      end
    else
      flash.now[:danger] = 'Invalid email/password combination'
      render 'new'
    end
  end

アクティベーションしてないユーザーがログインしようとすると、通知が出るように。
スクリーンショット 2020-01-30 12.33.27.png

11.3.3 有効化のテストとリファクタリング

アカウント有効化の統合テストを追加する。内容のベースは「正しい情報でユーザー登録を行った場合」のテスト。

ユーザー登録のテストにアカウント有効化を追加する。

test/integration/users_signup_test.rb

  def setup
    ActionMailer::Base.deliveries.clear
  end

省略

test "valid signup information with account activation" do #=> アカウント有効化を追加
    get signup_path
    assert_difference 'User.count', 1 do
      post users_path, params: { user: { name:  "Example User",
                                         email: "user@example.com",
                                         password:              "password",
                                         password_confirmation: "password" } }
    end

    assert_equal 1, ActionMailer::Base.deliveries.size
    user = assigns(:user)
    assert_not user.activated?
    # 有効化していない状態でログインしてみる
    log_in_as(user)
    assert_not is_logged_in?
    # 有効化トークンが不正な場合
    get edit_account_activation_path("invalid token", email: user.email)
    assert_not is_logged_in?
    # トークンは正しいがメールアドレスが無効な場合
    get edit_account_activation_path(user.activation_token, email: 'wrong')
    assert_not is_logged_in?
    # 有効化トークンが正しい場合
    get edit_account_activation_path(user.activation_token, email: user.email)
    assert user.reload.activated?
    follow_redirect! # assert_template 'users/show'
    assert_template 'users/show'
    assert is_logged_in? # assert is_logged_in? #=> signup 終えた人はログインも終わってるか?
  end

assignsメソッド

assignsメソッドとは、「コントローラーのインスタンス変数をテストするメソッド」。引数にはインスタンス変数(@user)をシンボル型(:user)で渡して使う。

参考
Rspecの基礎

これでテストは通過

次はユーザー操作の一部をコントローラからモデルに移動する。
流れとしては、
①activateメソッドを作成してユーザーの有効化属性を更新
②send_activation_emailメソッドを作成して有効化メールを送信

Userモデルにユーザー有効化メソッドを追加する

app/models/user.rb

private

# アカウントを有効にする
  def activate
    update_attribute(:activated,    true)
    update_attribute(:activated_at, Time.zone.now)
  end

# 有効化用のメールを送信する
  def send_activation_email
    UserMailer.account_activation(self).deliver_now
  end

ユーザーモデルオブジェクト経由でアカウントを有効化する

app/controllers/account_activations_controller.rb

def edit
    user = User.find_by(email: params[:email])
    if user && !user.activated? && user.authenticated?(:activation, params[:id])
      #Success => Signup
      #不要 user.update_attribute(:activated,    true)
      #不要 user.update_attribute(:activated_at, Time.zone.now)
      user.activate
      log_in user
      flash[:success] = "Account activated!"
      redirect_to user

ユーザーモデルオブジェクトからメールを送信する

app/controllers/users_controller.rb

# POST /users
  def create
    @user = User.new(user_params)
      if @user.save
        # Sucess
        @user.send_activation_email #=>signup後にactivation_emailを送りつける
        #不要 UserMailer.account_activation(@user).deliver_now
        flash[:info] = "Please check your email to activate your account."
        redirect_to root_url
      else

これでテストは通過

11.4 本番環境でのメール送信

SendGridの使い方

本番環境からメール送信するために、「SendGrid」というHerokuアドオン(Webサービス)を利用してアカウントを検証する。このサービスの利用のためにはクレジットカードの登録が必要(1日のメール数が最大400通までという制限があるが無料)。利用の場合は下記リンクにアクセスして入力する。
https://heroku.com/verify

参考
heroku へクレジットカード登録

スクリーンショット 2020-01-30 14.04.10.png

アドオンをアプリケーションに追加するには、次のコマンドを実行。

$ heroku addons:create sendgrid:starter

> heroku: Press any key to open up the browser to login(ログインしたくば、任意のキーを押されよ) 
→ Enter押す
> Opening browser to https://cli-auth.heroku.com/...
    Warning: Cannot open browser.
→ リンクからログインする(下記SS
> Logging in... done

image.png

ログインして利用可能状態になった。

アプリケーションでSendGridアドオンを使うには、
1. production環境のSMTPに情報を記入
2. 本番Webサイトのアドレスをhost変数に定義
が必要。

Railsのproduction環境でSendGridを使う設定

config/environments/production.rb

Rails.application.configure do
  .
  .
  .
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  host = '<自分のドメイン>.herokuapp.com'
  config.action_mailer.default_url_options = { host: host }
  ActionMailer::Base.smtp_settings = {
    :address        => 'smtp.sendgrid.net',
    :port           => '587',
    :authentication => :plain,
    :user_name      => ENV['SENDGRID_USERNAME'],
    :password       => ENV['SENDGRID_PASSWORD'],
    :domain         => 'heroku.com',
    :enable_starttls_auto => true

自分のドメインはheokuのアプリ開くかpersonalなどのページから確認。
ちなみに、SendGridの環境変数などを知りたい時は、

$ heroku config:get SENDGRID_USERNAME
> app686...@heroku.com(数字は適当)
$ heroku config:get SENDGRID_PASSWORD
>haiuekuryha436798

などで、herokuのスタータープランなどで作ってくれたメール等確認できる。

※ 注意
ここで重要なのが、

user_namepasswordのハッシュに実際の値を記入しないこと

ソースコードに直接機密情報を書き込むのは危険であり(ソースコードがハックされたらout)、そのような情報は環境変数に記述し、そこからアプリケーションに読み込む必要がある。

ここで一応テスト。
テストは通過

ここからはいつも通り、

$ git add -A
$ git commit -m "Finish ch11"
$ git checkout master
$ git merge account-activation
$ rails t
$ git push heroku master
$ heroku pg:reset DATABASE
> 左赤字(アプリ名〇〇_app)
$ heroku run rails db:migrate
$ heroku run rails db:seed

本番環境でアカウント作成して

スクリーンショット 2020-01-30 15.03.26.png

ちゃんと自分のGmailにメールが送信された

スクリーンショット 2020-01-30 15.08.52.png

Activateをクリックでログインに成功。

スクリーンショット 2020-01-30 15.12.43.png

ちなみに忘れたりしてもう一度Activateをクリックすると既に有効化されているため、下記のような表示になる。

image.png

終了。
 

参考
第11章アカウントの有効化

Ruby on Rails チュートリアル 第11章 アカウント有効化(AcctionMailer Activation)やSendGridの使い方など

6
0
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
6
0