##はじめに
Railsチュートリアル11章の内容を、少しでも理解の助けとなればと思い、割としっかり目に整理しました!
備忘録です。
##前提
Railsチュートリアル1〜10章までの内容が完了していること。
##内容
Railsチュートリアル11章の__アカウント有効化機能の実装手順__を、前中後半の3回に分けて整理しました。
中編である今回は、__アカウント有効化メール送信機能の実装__をしていきます!
前編→AccountActivationsリソースの作成
後編→アカウント有効化機能の実装
##1.アカウント有効化用のメールを送信する機能の実装
●__データのモデル化が完了したので、次はアカウント有効化メールの送信に必要な機能を記述していく__。
●__メールを送信する機能を実装するには、Action Mailerライブラリを使って、Userのメイラーを作成する必要がある__。
➡︎メイラーは、Usersコントローラのcreateアクションで、ユーザーへ有効化リンクをメール送信させるために使う。
➡︎メイラーはコントローラのアクションと似ており、メールのテンプレートを、ビューと同じ要領で定義できる。
→有効化トークンと有効化するアカウントのアドレスのリンクは、このテンプレートの中で使う。
####1-1.送信メールのテンプレートを作成していく
●まず、__Userメイラーを作成__する。
➡︎$ rails g mailer UserMailer account_activation password_reset
→UserMailerはメイラー名で、その後には必要となるメソッドを入力する。
→password_resetメソッドは、後にパスワード再設定機能を実装する際に使うので、序でに作成しておく。
➡︎メイラーを生成すると、ついでにビューのテンプレートがファイルごとに2つ生成される。
→1つはテキストメール用のテンプレートで、1つはHTMLメール用のテンプレート。
●生成されたメイラーをカスタマイズして、有効化メールで使えるようにする。
➡Applicationメイラー
→app/mailers/application_mailer.rb
→デフォルトでfromアドレスが設定されていると思うが、これを削除して、実際に使えるメールアドレスに書き換える。
➡Userメイラー
→app/mailers/user_mailer.rb
→コマンドを実行した際に作成したメソッドの内、account_activationメソッドをカスタマイズしていく。
→まずメソッド名をaccount_activation(user)とし、ユーザーのデータを取得できるよう明示的に引数を記述してあげる。
→取得したユーザーは、ビューで利用できるように@userインスタンス変数へ代入されるようにする。
→ユーザーへメールが送信されるよう処理を記述し、件名も付け加えておく。
→mail to: user.email, subject: "件名"
●__ユーザーへ送信するための有効化リンクを作成する準備をする__。
➡︎ユーザーをメールアドレスで検索し、有効化トークンを認証できるよう処理を記述していく。
➡︎そのためには、リンクにメールアドレスとトークンの両方を組み込む必要がある。
→__アカウントを有効化するリンクにトークンを組み込む方法__。
→AccountActivationsリソースにて有効化はモデル化したので、有効化トークンは名前付きルートの引数で使われることになる。
→つまり、edit_account_activation_url(@user.activation_token)となる。
→上記の名前付きルートは、下記の形式のURLを生成する。
→http://www.example.com/account_activations/(new_tokenメソッドで生成されたランダム文字列)/edit
→ちなみに上記のトークン部分はユーザーIDと同じ働きをするため、AccountActivationsコントローラのeditアクション内で、params[:id]とすれば参照するできる。
→というわけで、トークンの組み込み完了。
→__今度は、有効化リンクにメールアドレスも組み込む__。
→リンクにメールアドレスを組み込むには、クエリパラメータを使う必要がある。
→クエリパラメータとは、URLの末尾で「?」に続けてキーと値のペアを記述したもの。
→要するに、http://<省略>/edit?email=user%40example.comみたいな感じ。
→「%40」の意味は@と一緒。URLでは@記号が使えないので、エスケープと呼ばれる手法により変換している。
→上記のようにURLにクエリパラメータを組み込むには、名前付きルートにてユーザーのメールアドレスを参照できるようなハッシュを記述してあげればOK。
→どういうことかというと、edit_account_activation(@user.activation_token, email:@user.email)とすればOK。
→上記のように名前付きルートでクエリパラメータを書き加えると、Railsが自動的にエスケープを行ってくれため、正常なリンクとして動作してくれる。
→さらに、editアクションでメールアドレスを参照するためにparams[:email]とする際は、自動的にスケープを解除してくれる。便利。
➡︎︎︎これで、リンクを作成する準備が完了した。
●テンプレートビューにて、リンクを作成する。
➡︎通常のERb同様ビューは自由にカスタマイズできるので、挨拶文にユーザー名を含め、有効化リンクを記述することにする。
➡︎︎︎アカウント有効化のテキストビューにて。
→挨拶とユーザーの名前を表示する記述をする。
→ERB内でeditへの名前付きルートを使って、有効化トークンとメールアドレスを組み込んだリンクを作成する。
➡︎アカウント有効化のHTMLビューにて。
→挨拶とユーザーの名前を表示する記述をする。
→ERb内でlink_toタグで、上記同様editへの名前付きルートを使って、有効化トークンとメールアドレスを組み込んだリンクを作成する。
ターミナル
#1-1.Userメイラーの作成
$ rails g mailer UserMailer account_activation password_reset
>```ruby:app/mailers/application_mailer.rb
#1-1.Applicationメイラーのカスタマイズ。
class ApplicationMailer > ActionMailer::Base
default from: "実際に有効化メール送信で使うメアド"
layout 'mailer'
end
app/mailers/user_mailer.rb
#1-1.Userメイラーのカスタマイズ。
class UserMailer < ApplicationMailer
def account_activation(user)
@user = user
mail to: user.email, subject "件名"
#省略
end
>```ruby:app/views/user_mailer/account_activation.text.erb
#1-1.アカウント有効化のテキストビュー。
こんにちは、<%= @user.name %>
下記のリンクをクリックして、アカウントを有効化してください。
<%= edit_account_activation_url(@user.activation_token,
email: @user.email) %>
app/views/user_mailer/account_activation.html.erb
#1-1.アカウント有効化のHTMLビュー。
こんにちは、<%= @user.name %>
下記のリンクをクリックして、アカウントを有効化してください。
<%= link_to "有効化する", edit_account_activaation_url(@user.activation_token,
email: @user.email) %>
####1-2.送信メールのプレビュー
●メールメッセージをその場で簡単にプレビューする。
➡︎アプリケーションのdevelopment環境の設定に手を加える必要がある。
→config/environments/development.rbファイルへ移動する。
→ホスト名は、各々のdevelopment環境に合わせて変更する必要があるので注意。
→例えば、ローカル環境で開発しているなら「'localhost:3000'」に変更しなければ動作しない。
→developmentサーバーを再起動して、設定を読み込む。
➡アカウント有効化のプレビューメソッドを定義する。
→test/mailers/previews/user_mailer_preview.rbファイルへ移動する。
→account_activationメソッドはこのままでは動作しないため、動作させるための処理を記述していく必要がある。
→まず、開発用DBの最初のユーザーを取得するためのuser変数を定義する。
→さらに、ビューのテンプレートでアカウント有効化のトークンが必要となるため、ユーザーの有効化トークンにUser.new_tokenを代入する処理を記述する必要がある。
→有効化トークンは、仮の属性なのでDBのユーザーは実際にはこの値を持っているわけではない。
→上記で取得したユーザーをUserMailer.account_activationメソッドの引数に渡す。
➡︎以上のコードを実装したことで、指定のURLでアカウント有効化メールをプレビューできるようになった。
>```ruby:config/environments/development.rb
#1-2.development環境のメール設定。
Rails.application.configure do
.
.
.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = '各々のホストのURLを記述'
config.action_mailer.default_url_options = { host: host, protocol: 'https' }
.
.
.
end
test/mailers/previews/user_mailer_preview.rb
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
#1-2.アカウント有効化のプレビューメソッド定義。
def account_activation
user = User.first
user.activation_token = User.new_token
UserMailer.account_activation(user)
end
.
.
.
end
####2-3.送信メールのテストを書いていく
●メールプレビューのテストを作成する。
➡︎test/mailers/user_mailer_test.rbに、Userメイラーの簡単なテスト例が自動生成されているので利用する。
➡︎assert_matchというメソッドがとても便利で、正規表現によって文字列をテストすることができる。
→例.assert_match 'foo', 'foobar' #true
➡︎assert_matchメソッドを使い、名前、有効化トークン、エスケープ済みメールアドレスが本文に含まれているかどうかをテストする。
→ちなみに、CGI.escapse(use.email)とすることで、テスト用のユーザーのメールアドレスをエスケープすることができる。
→それから、このCGI.escape部分を削除すると、テストはパスしない。
➡︎加えてテストコードのfixtureユーザーに、有効化トークンを取得させる記述をする。そうしないと空白になる。
➡︎テストRED。
➡︎このテストがパスするには、テストファイル内のドメイン名を正しく設定する必要がある。
→config/environments/test.rbへ移動。
→テストのドメインホストを、host: '正しいドメイン名'とする。
➡︎テストGREEN。
>```ruby:test/mailers/user_mailer_test.rb
#1-3.現在までのメール機能実装に関するテストを書いていく。RED。
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 [各々が設定したメールアドレスを記述], 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
#1-3.テストのドメインホストを設定する。
Rails.application.configure do
.
.
.
config.action_mailer.delivery_method = :test
config.action_mailer.default_url_options = { host: '正しいホストを記述' }
.
.
.
end
####2-4.ユーザーのcreateアクションを更新。
●createアクション内のユーザー登録機能に、アカウント有効化機能を追加する。
➡︎app/controllers/users_controller.rbファイルへ移動。
→ユーザーの新規登録が完了しユーザーが保存された後、そのユーザーへアカウント有効化メールを送信する処理を記述する。
→UserMailer.account_activation(@user).deliver_now
→ユーザーへメールを確認するよう促すフラッシュを表示させ、リダイレクト先はルートURLに変更。
→この時同時に、登録が完了するとログインする機能を削除する。
●上記の変更により、テストスイートがREDになった。
➡︎integration/users_signup_test.rbへ移動。
→失敗するテストを一旦コメントアウト。
→新規登録後にログインさせないようにしたので、ユーザープロフページが表示されているかどうかの検証と、ユーザーのログインを検証する記述をコメントアウトにする。
→assert_template 'users/show'と、assert is_logged_in?
→アカウント有効化機能を実装した後、テストを書くのでそこで修正する。
>```ruby:app/controllers/users_controller.rb
class UsersController < ApplicationController
.
.
.
def create
@user = User.new(user_params)
if @user.save
#1-4.新規登録後、ユーザーへアカウント有効化のメールを送信する。(ログインは削除)
UserMailer.account_activation(@user).deliver_now
flash[:info] = "Please check your email to activate your account."
redirect_to root_url
else
render 'new'
end
end
.
.
.
end
##最後に
中編の__アカウント有効化用メール送信機能の実装__が完了しました。
前編→AccountActivationsリソースの作成
後編→アカウント有効化機能の実装