#Railsチュートリアル 11章
##11章アカウントの有効化
###この章の趣旨
- SMS認証的なものを作る
- メールをユーザーに送ってユーザーがメールに記載されているURLをクリックすることで認証とする機能を追加する
- 有効化トークン(文字列)を含めたリンクをメールで送信する
###11.1 AccountActivationsリソース
まずはUserモデルに必要なカラムを追加する
###11.1.1 AccountActivationsコントローラ
まずはAccountActivationsコントローラを生成。
$ rails generate controller AccountActivations
まずは、名前付きルートを扱えるように、ルーティングにアカウント有効化用のresources行を追加
Rails.application.routes.draw do
root 'static_pages#home'
get '/help', to: 'static_pages#help'
get '/about', to: 'static_pages#about'
get '/contact', to: 'static_pages#contact'
get '/signup', to: 'users#new'
get '/login', to: 'sessions#new'
post '/login', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
resources :users
resources :account_activations, only: [:edit] #追加
end
追加した行はaccount_activation/トークン/edit
のURLでルートを拾う
###11.1.2 AccountActivationのデータモデル
送信メールの有効化トークンとデータベースの有効化トークンを同じにすると、セキュリティが危ないので
なのでパスワード設定と同様に仮想的な属性を使ってハッシュ化した文字列をデータベースに保存する
仮想属性の有効化トークンは
user.activation_token
この値がuserと合っていれば認証OKとなる
ユーザーの認証は
user.authenticated?(:activation, token)
autenticated?メソッドを使ってメールについている有効化トークンと仮想属性の有効化トークンを比べる
続いて、activated属性を追加して論理値を取る
if user.activated? ...
既に有効化されているか、いないかチェックする デフォルトはfalse状態
最後に ユーザーを有効にしたときの日時も念のために記録
Userモデルに上記3つのカラムを追加するための
次のマイグレーションをコマンドラインで実行
rails generate migration add_activation_to_users \
activation_digest:string activated:boolean activated_at:datetime
class AddActivationToUsers < ActiveRecord::Migration[6.0]
def change
add_column :users, :activation_digest, :string
add_column :users, :activated, :boolean, default: false #default設定する
add_column :users, :activated_at, :datetime
end
end
マイグレーションを実行
###Activationトークンのコールバック
Userモデルにアカウント有効化のコードを追加する
class User < ApplicationRecord
attr_accessor :remember_token, :activation_token #activation_token属性を追加
before_save :downcase_email #saveの前にemail小文字化
before_create :create_activation_digest #ユーザが作成される前にcreate...を呼び出す
validates :name, presence: true, length: { maximum: 50 }
.
.
.
private #privateより下に記述したメソッドは外部に公開されない 以下consoleで確認
# メールアドレスをすべて小文字にする
def downcase_email
self.email = email.downcase
end
# 有効化トークンとダイジェストを作成および代入する
def create_activation_digest
self.activation_token = User.new_token #アクセサーで定義ずみ 認証用のtokenを代入 ※認証と同じ文字列
self.activation_digest = User.digest(activation_token) #Userモデルのdigestカラムに上で定義した認証用トークンを代入
end
end
※クラス内でprivateキーワードより下に記述したメソッドは自動的に非公開となる
$ rails console
>>User.first.create_activation_digest
NoMethodError: private method `create_activation_digest' called for #<User>
###サンプルユーザーの生成とテスト
サンプルデータとfixtureも更新し、テスト時のサンプルとユーザーを事前に有効化しておく
※Time.zone.nowはRailsの組み込みヘルパーであり、サーバーのタイムゾーンに応じたタイムスタンプを返す
# メインのサンプルユーザーを1人作成する
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のユーザーも同様に行う (コード省略)
マイグレーションファイルも更新
$ rails db:migrate:reset
$ rails db:seed
###11.2 アカウント有効化のメール送信
- メールのテンプレートを作成する
- ビューと同様にメールをブラウザでプレビューできる
###11.2.1 送信メールのテンプレート
rails generate
でコントローラー同様にメイラーを作成する ※メイラーはメールを送るものです
$ rails generate mailer UserMailer account_activation password_reset
これで
account_activationメソッドと、password_resetメソッドが生成
さらにビューのテンプレートが2つずつ生成される
1つはテキストメール用のテンプレート、1つはHTMLメール用のテンプレート。
class ApplicationMailer < ActionMailer::Base
default from: "noreply@example.com" #メールのfromをカスタマイズした
layout 'mailer'
end
class UserMailer < ApplicationMailer
def account_activation(user)
@user = user #@userインスタンス変数を作成
mail to: user.email, subject: "Account activation" #subject:はメールの件名
end
def password_reset
@greeting = "Hi"
ail to: "to@example.org"
end
end
今時点はtestはred
メールのテンプレートにクリックしてもらうURLを追加する
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) %>
#editアクションへurlを送る urlの内容はtokenとemail
HTMLビュー
<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) %>
####edit_account_activation_url(@user.activation_token,email:@user:email)について解説
edit_account_activation_urlはroutes
においた
resources :account_activations, only: [:edit]
にリクエストを送信する
実際のURLはこんな感じになる
https://www.example.com/account_activations/q5lt38hQDc_959PVoo6b7A/edit
引数の@user.activation_token,email:@user:email
は
user.rb
で定義したactivation_token と user.emailを指す
# 有効化トークンとダイジェストを作成および代入する
def create_activation_digest
self.activation_token = User.new_token #アクセサーで定義ずみ 認証用のtokenを代入 ※認証と同じ文字列
self.activation_digest = User.digest(activation_token) #Userモデルのdigestカラムに上で定義した認証用トークンを代入
end
つまりURLの末尾に .../認証用のtoken/user.emailという形になる
/users/1/editの「1」のようなユーザーIDと同じ役割を果たす
認証用のトークンは、AccountActivationsコントローラのeditアクションで,paramsハッシュでparams[:id]として参照可能なので
edit_account_activation_url(@user.activation_token, email: @user.email)
で
認証トークンとメールアドレスを取得できる
※参考 emailアドレスは@マークがついている→example@example.com
@マークはURLでは利用できないので、(利用できない文字を回避することをエスケープという)
edit_account_activation_url(@user.activation_token, email: @user.email)
のように
名前付きルートでクエリパラメータを定義すると、Railsが特殊な文字を自動的にエスケープしてくれます。
コントローラでparams[:email]からメールアドレスを取り出すときには、自動的にエスケープを解除してくれます。
→``account_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.com``
→@が%40になっている
###11.2.2 送信メールのプレビュー
特定のURLをクリックすることでメールプレビューが使える
利用するにはアプリケーションのdevelopment環境の設定に手を加える必要がある。
development環境のメール設定
Rails.application.configure do
.
.
.
config.action_mailer.raise_delivery_errors = false
host = 'example.com' # ここをコピペすると失敗します。自分の環境のホストに変えてください。
# クラウドIDEの場合
config.action_mailer.default_url_options = { host: host, protocol: 'https' }
# localhostで開発している場合
# config.action_mailer.default_url_options = { host: host, protocol: 'http' }
.
.
.
end
ホスト名 'example.com' の部分は、各自のdevelopment環境に合わせて変更する
host = '.vfs.cloud9.us-east-2.amazonaws.com' # クラウドIDE
config.action_mailer.default_url_options = { host: host, protocol: 'https' }
※'はサーバーのURLを入れる
もしローカル環境で開発している場合
host = 'localhost:3000' # ローカル環境
config.action_mailer.default_url_options = { host: host, protocol: 'http' }
特に2番目の例では、httpsが暗号化なしのhttpに変わっている
Userメイラーはプレビューファイルを自動生成しており、それのテンプレートを変更する
# Preview all emails at http://localhost:3000/rails/mailers/user_mailer
class UserMailerPreview < ActionMailer::Preview
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/account_activation
def account_activation
user = User.first #user変数を定義 Userモデルの1番初め
user.activation_token = User.new_token #userのactivation_tokenカラムにtokenを代入
UserMailer.account_activation(user)
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset
UserMailer.password_reset
end
end
指定のURLでメールをプレビューできる
http://localhost:3000/rails/mailers/user_mailer/account_activation
localhostの部分をhost=に代入したページを挿入する
###11.2.3 送信メールのテスト
railsによって自動でtestが作られているのでそれを利用してtestする
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 #user.nameは入っているか
assert_match user.activation_token, mail.body.encoded #認証トークンは入っているか
assert_match CGI.escape(user.email), mail.body.encoded #@マークは%に変わってるか
end
end
今時点はまだred
※assert_matchメソッド
→正規表現で文字列をテストできる 指定した文字列がは良いているか?チェックする
assert_match 'foo', 'foobar' # true
assert_match 'baz', 'foobar' # false
assert_match /\w+/, 'foobar' # true
assert_match /\w+/, '$#!*+@' # false
※CGI.escape(user.email)
テスト用のユーザーのメールアドレスをエスケープする
このテストがパスするには、テストファイル内のドメイン名を正しく設定する必要がある
Rails.application.configure do
.
.
.
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { host: 'example.com' }
.
.
.
end
これでtestはpassする
###11.2.4 ユーザーのcreateアクションを更新
-
createアクションはuserが新規登録するアクション
-
ユーザが新規登録した後に、認証メールを送る機能を追加する
↓変更前のcreateアクション
def create
@user=User.new(user_params)
if @user.save
log_in @user #log_inしてるか
flash[:success] = "Welcome to the Sample App!"
redirect_to @user #userのshowビューへ送る
else
render 'new'
end
end
変更後のcreateアクション
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
UserMailer.account_activation(@user).deliver_now
#メールを送信する
#deliver_nowは、今すぐに送信したい場合に使用
flash[:info] = "Please check your email to activate your account."
redirect_to root_url #homeへ送るように
else
render 'new'
end
end
.
.
.
end
createの挙動を少し変えたためtestがredになった
合っていないtestは一旦コメントアウトし、後で戻す
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
end
test "valid signup information" 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
follow_redirect!
# assert_template 'users/show'
# assert is_logged_in?
end
end
これで実際にはmail飛んでないが、serverで確認することができる
サーバーログ こんな感じ
UserMailer#account_activation: processed outbound mail in 5.1ms
Delivered mail 5d606e97b7a44_28872b106582df988776a@ip-172-31-25-202.mail (3.2ms)
Date: Fri, 23 Aug 2019 22:54:15 +0000
From: noreply@example.com
To: michael@michaelhartl.com
Message-ID: 5d606e97b7a44_28872b106582df988776a@ip-172-31-25-202.mail
Subject: Account activation
Mime-Version: 1.0
Content-Type: multipart/alternative;
boundary="--==_mimepart_5d606e97b6f16_28872b106582df98876dd";
charset=UTF-8
Content-Transfer-Encoding: 7bit
メールの内容もみれる
----==_mimepart_5d606e97b6f16_28872b106582df98876dd
Content-Type: text/plain;
charset=UTF-8
Content-Transfer-Encoding: 7bit
Hi Michael Hartl,
Welcome to the Sample App! Click on the link below to activate your account:
https://0ebe1dc6d40e4a4bb06e0ca7fe138127.vfs.cloud9.us-east-2.
amazonaws.com/account_activations/zdqs6sF7BMiDfXBaC7-6vA/
edit?email=michael%40michaelhartl.com
↑認証トークンとメールアドレスもしっかり入っている
##11.3 アカウントを有効化する
- AccountActivationsコントローラのeditアクションを書く
- editアクションは認証メールをクリックした後の受け取り機能
- テストも実施
- リファクタリングも行う
###11.3.1 authenticated?メソッドの抽象化
- authnticatedメソッドをいろんなシーンで使えるようにする
最終的にautenticatedメソッドを以下のように書き換える
class User < ApplicationRecord
.
.
.
# トークンがダイジェストと一致したらtrueを返す
def authenticated?(attribute, token)
digest = send("#{attribute}_digest")
return false if digest.nil?
BCrypt::Password.new(digest).is_password?(token)
end
.
.
.
end
元々のautenticatedメソッド↓↓
# トークンがダイジェストと一致したらtrueを返す
def authenticated?(remember_token)
return false if remember_digest.nil?
BCrypt::Password.new(remember_digest).is_password?(remember_token)
end
元々autenticatedメソッドはremember_tokenを引数にとり
クッキーのセクションがUserテーブルのremember_digestカラムと一致すればtrueを返すメソッド
ここに引数を1つ加え、digest = send("#{attribute}_digest")
という変数展開をして変更を加えている
まずはsend
について解説
sendメソッドは渡されたオブジェクトにメッセージを送ることにより、呼び出すメソッドを動的に決めれる
$ rails console
>> a = [1, 2, 3]
>> a.length
=> 3
>> a.send(:length)
=> 3
>> a.send("length")
=> 3
変数aに(引数のメソッド)を渡しているため 同じ結果になる
もう1つ例
>> user = User.first
>> user.activation_digest
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> user.send(:activation_digest)
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> user.send("activation_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
>> attribute = :activation
>> user.send("#{attribute}_digest")
=> "$2a$10$4e6TFzEJAVNyjLv8Q5u22ensMt28qEkx0roaZvtRcp6UZKRM6N9Ae"
sendの引数内で変数展開をしてメソッドを正しく認識できる
つまり
send(#{変数}_digest) は
↓↓
#{attribute}_digest
シンボルと文字列どちらを使った場合でも、上のコードは次のように文字列に変換されます。
activation_digest
引数activatinとした場合
つまり
digest = send("#{attribute}_digest")
は引数attribute
を利用して”変数_digest”→変数を変えれば
-
activation_digest
にも password_digest
-
remember_digest
にもなれる
このような受け取ったパラメータ変数によって呼び出すメソッドを変えることを「メタプログラミング」と呼ばれ
メタプログラミングとは「プログラムでプログラムを作成する」ことです
これでautenticated?メソッドは メールの認証でも、クッキーの認証でも使えるようになった
次にすすむ前に、関連するcurrent_userメソッド (sessions_helper記載)とnilダイジェストのテスト(user_test.rb)の両方で、
authenticated?が古く、引数も2つではなくまだ1つのままだから書き換えます
module SessionsHelper
.
.
.
# 現在ログイン中のユーザーを返す(いる場合)
def current_user
if (user_id = session[:user_id])
@current_user ||= User.find_by(id: user_id)
elsif (user_id = cookies.signed[:user_id])
user = User.find_by(id: user_id)
if user && user.authenticated?(:remember, cookies[:remember_token]) #引数2つ
log_in user
@current_user = user
end
end
end
.
.
.
end
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
@user = User.new(name: "Example User", email: "user@example.com",
password: "foobar", password_confirmation: "foobar")
end
.
.
.
test "authenticated? should return false for a user with nil digest" do
assert_not @user.authenticated?(:remember, '') #引数2つ
end
end
これでtestもpassして、autenticated?メソッドは抽象化できました
###11.3.2 editアクションで有効化
- editアクションでユーザーの認証をする
- メールで送った認証トークンと、Userテーブルのactivation_digestが同じであればログイン可能
- 異なる場合はログインせずに、ルートに戻す処理を行う
editアクションで、paramsハッシュで渡されたメールアドレスに対応するユーザーを認証
if user && !user.activated? && user.authenticated?(:activation, params[:id])
#もしuserが存在し、かつuserがactivatedがtrueかつactivation_digestがparams[:id](認証トークン)と一緒なら
!user.activated?という記述は、既に有効になっているユーザーを誤って再度有効化しないために必要
上の論理値に基いてユーザーを認証するには、ユーザーを認証してからactivated_atタイムスタンプを更新する必要がある
user.update_attribute(:activated, true)
#userテーブルのactivatedカラムをtrueにアップデートする
user.update_attribute(:activated_at, Time.zone.now)
#userテーブルのactivated_atカラムを現在時間にアップデートする
上のコードをeditアクションで使います。
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation, params[:id])
user.update_attribute(:activated, true)
user.update_attribute(:activated_at, Time.zone.now)
log_in user
flash[:success] = "Account activated!"
redirect_to user
else
flash[:danger] = "Invalid activation link"
redirect_to root_url
end
end
end
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
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
#トークンが無効になるようなことはめったにないが、もしそうなった場合はルートURLにリダイレクトされる仕組み
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
def destroy
log_out if logged_in?
redirect_to root_url
end
end
###11.3.3 有効化のテストとリファクタリング
- アカウント認証の統合テストを追加する
- 前に作ったユーザー登録のテストを修正する
ユーザー登録のテストにアカウント有効化を追加
require 'test_helper'
class UsersSignupTest < ActionDispatch::IntegrationTest
def setup
ActionMailer::Base.deliveries.clear #ハイライト
end
test "invalid signup information" do
get signup_path
assert_no_difference 'User.count' do
post users_path, params: { user: { name: "",
email: "user@invalid",
password: "foo",
password_confirmation: "bar" } }
end
assert_template 'users/new'
assert_select 'div#error_explanation'
assert_select 'div.field_with_errors'
end
test "valid signup information with account activation" do
get signup_path #新規登録
assert_difference 'User.count', 1 do #userのcountが1になったか
post users_path, params: { user: { name: "Example User", # paramsにユーザーデータin
email: "user@example.com",
password: "password",
password_confirmation: "password" } }
end
assert_equal 1, ActionMailer::Base.deliveries.size #送ったメールが1通かどうか
user = assigns(:user) #assignsはインスタンス変数にアクセスできるようになる
assert_not user.activated? #userカラムのactivatedがfalseでないか
# 有効化していない状態でログインしてみる
log_in_as(user) #userでlog_inする
assert_not is_logged_in? #log_inしていないか確認
# 有効化トークンが不正な場合
get edit_account_activation_path("invalid token", email: user.email) #おかしいurl (トークン)を取得
assert_not is_logged_in? #loginしていないか確認
# トークンは正しいがメールアドレスが無効な場合
get edit_account_activation_path(user.activation_token, email: 'wrong') #おかしいurl(メール)取得
assert_not is_logged_in? #loginしていないか確認
# 有効化トークンが正しい場合
get edit_account_activation_path(user.activation_token, email: user.email) #正しいurl取得
assert user.reload.activated? #reloadしてactivatedがtrueか確認
follow_redirect! #showページに飛ばす
assert_template 'users/show' #showビューが表示されるか
assert is_logged_in? #ログイン状態になったか
end
end
assert_equal 1, ActionMailer::Base.deliveries.size
は、配信されたメッセージがきっかり1つであるかどうかを確認する。
配列deliveriesは変数なので、setupメソッドでこれを初期化しておかないと、並行して行われる他のテストでメールが配信されたときにエラーが発生する
これでtestはpassする
####リファクタリングする
activateメソッドを作成してユーザーの有効化属性を更新し、send_activation_emailメソッドを作成して有効化メールを送信します。この新しいメソッドをリスト 11.35に示します。また、リファクタリングされたアプリケーションコードをリスト 11.36とリスト 11.37に示します。
Userモデルにユーザー有効化メソッドを追加する
class User < ApplicationRecord
.
.
.
# アカウントを有効にする
def activate
#update_attribute(:activated, true) #activatedカラムをtrueにupdateする
#update_attribute(:activated_at, Time.zone.now) #activated_atを現在時刻にupdateする
update_columns(activated: true, activated_at: Time.zone.now) #演習でこのように書き換える
end
# 有効化用のメールを送信する
def send_activation_email
UserMailer.account_activation(self).deliver_now #メールを送る
end
private
.
.
.
end
ユーザーモデルオブジェクトからメールを送信する
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
@user.send_activation_email #user.rbで定義したsend_activation_emailを呼び出す(メール送る)
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
.
.
.
end
ユーザーモデルオブジェクト経由でアカウントを有効化する
class AccountActivationsController < ApplicationController
def edit
user = User.find_by(email: params[:email])
if user && !user.activated? && user.authenticated?(:activation, params[:id])
user.activate #user.rbで定義したactiveメソッドを呼び出す→activatedを更新
log_in user
flash[:success] = "Account activated!"
redirect_to user
else
flash[:danger] = "Invalid activation link"
redirect_to root_url
end
end
end
これでtestはpassする
###11.4 本番環境でのメール送信
開発環境ではなく、本番環境でメールを送信できるようにする
そのために無料のサービスを利用し、送信の設定をする
次にアプリの設定とデプロイをする
本番環境からメール送信するために、「Mailgun」というHerokuアドオンを利用
アプリケーションでMailgunアドオンを使うには、production環境のSMTPに情報を記入する
Rails.application.configure do
.
.
.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
host = '<your heroku app>.herokuapp.com' #自分のherokuのURLを入力
config.action_mailer.default_url_options = { host: host }
ActionMailer::Base.smtp_settings = {
:port => ENV['MAILGUN_SMTP_PORT'],
:address => ENV['MAILGUN_SMTP_SERVER'],
:user_name => ENV['MAILGUN_SMTP_LOGIN'],
:password => ENV['MAILGUN_SMTP_PASSWORD'],
:domain => host,
:authentication => :plain,
}
.
.
.
end
一旦gitに上げて、heroku本番環境にあげる
$ rails test
$ git add -A
$ git commit -m "Add account activation"
$ git checkout master
$ git merge account-activation
$ rails test
$ git push
$ git push heroku
$ heroku run rails db:migrate
MailgunのHerokuアドオンを追加するために、次のコマンドを実行
$ heroku addons:create mailgun:starter
クレカを事前に登録しておかないとエラーが出る
受信メールの認証を行います。以下のコマンドを打つと、Mailgun ダッシュボードのURLが表示されるのでブラウザで開きます。
ブラウザの画面左側の「Sending」→「Domains」のリストにある「sandbox」で始まるサンドボックスドメインを選択
画面右側の「Authorized Recipients」から受信メールアドレスを認証し、本番環境でのメール送信準備は完了
あとは本番環境で新規アカウントを作成してみると正常に作動する
###まとめ
非常に難しい内容でしたが、1つ1つ意味を噛み砕いて行けばなんとかできました...