11.2 アカウント有効化のメール送信
11.2.1 送信メールのテンプレート
メイラーは、モデルやコントローラと同様にrails generateで生成できます。
rails generate mailer UserMailer account_activation password_reset
今回必要となるaccount_activationメソッドと、
第12章で必要となるpassword_resetメソッドが生成されました。
生成したメイラーごとに、ビューのテンプレートが2つずつ生成されます。
1つはテキストメール用のテンプレート、
1つはHTMLメール用のテンプレートです。
アカウント有効化メイラーのテキストビュー (自動生成)
app/views/user_mailer/account_activation.text.erb
UserMailer#account_activation <%= @greeting %>, find me in app/views/user_mailer/account_activation.text.erb
アカウント有効化メイラーのHTMLビュー (自動生成)
app/views/user_mailer/account_activation.html.erb
<h1>UserMailer#account_activation</h1> <p> <%= @greeting %>, find me in app/views/user_mailer/account_activation.html.erb </p>
生成されるHTMLメイラーのレイアウトやテキストメイラーのレイアウトはapp/views/layoutsで確認できます。
生成されたコードにはインスタンス変数@greetingも含まれています。
このインスタンス変数は、ちょうど普通のビューでコントローラのインスタンス変数を利用できるのと同じように、メイラービューで利用できます。
生成されたApplicationメイラーapp/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base default from: "from@example.com" layout 'mailer' end
生成されたUserメイラー
app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer def account_activation @greeting = "Hi" mail to: "to@example.org" end def password_reset @greeting = "Hi" mail to: "to@example.org" end end
生成されたテンプレートをカスタマイズして、実際に有効化メールで使えるようにします。
次に、ユーザーを含むインスタンス変数を作成してビューで
使えるようにし、user.emailにメール送信します。
mailにsubjectキーを引数として渡しています。
この値は、メールの件名にあたります。
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(user)
@user = user
mail to: user.email, subject: "Account activation"
end
def password_reset
@greeting = "Hi"
mail to: "to@example.org"
end
end
テンプレートビューは、通常のビューと同様ERBで自由にカスタマイズできます。
ここでは挨拶文にユーザー名を含め、カスタムの有効化リンクを追加します。
この後、Railsサーバーでユーザーをメールアドレスで検索して有効化トークンを認証できるようにしたいので、
リンクにはメールアドレスとトークンを両方含めておく必要があります。
AccountActivationsリソースで有効化をモデル化したので、
トークン自体はリスト 11.1で定義した名前付きルートの引数で使われます。
edit_account_activation_url(@user.activation_token, …)
ここで思い出してみましょう。
edit_user_url(user)
上のメソッドは、次の形式のURLを生成します。
http://www.example.com/users/1/edit
これに対応するアカウント有効化リンクのベースURLは次のようになります。
http://www.example.com/account_activations/q5lt38hQDc_959PVoo6b7A/edit
URLで使えるようにBase64でエンコードされています。
/users/1/editの「1」のようなユーザーIDと同じ役割を果たします。
このトークンは、特にAccountActivationsコントローラのeditアクションではparamsハッシュでparams[:id]として参照できます。
クエリパラメータを使って、このURLにメールアドレスもうまく組み込んでみましょう。
クエリパラメータとは、URLの末尾で疑問符「?」に続けてキーと値のペアを記述したものです
acount_activations/q5lt38hQDc_959PVoo6b7A/edit?email=foo%40example.com
このとき、メールアドレスの「@」記号がURLでは「%40」となっている点に注目してください。
これは「エスケープ」と呼ばれる手法で、通常URLでは扱えない文字
を扱えるようにするために変換されています。
Railsでクエリパラメータを設定するには、
名前付きルートに対して次のようなハッシュを追加します。
edit_account_activation_url(@user.activation_token,
email: @user.email)
アカウント有効化のテキストビュー
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,mail:@user.email) %>
演習
1:コンソールを開き、CGIモジュールのescapeメソッドでメールアドレスの文字列をエスケープできることを確認してみましょう。
このメソッドで”Don’t panic!”をエスケープすると、どんな結果になりますか?
CGI.escapeを使ってエスケープする
> CGI.escape(“Don’t panic!”)
=> “Don%27t+panic%21”
11.2.2 送信メールのプレビュー
定義したテンプレートの実際の表示を簡単に確認するために、
メールプレビューという裏技を使ってみましょう。
Railsでは、特殊なURLにアクセスするとメールのメッセージをその場でプレビューすることができます。
メールを実際に送信しなくてもよいので大変便利です。
これを利用するには、
アプリケーションのdevelopment環境の設定に手を加える必要があります。
config/environments/development.rb
Rails.application.configure do
.
.
.
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :test
host = 'example.com' # ここをコピペすると失敗します。自分の環境に合わせてください。
config.action_mailer.default_url_options = { host: host, protocol: 'https' }
.
.
.
end
host = 'rails-tutorial-mhartl.c9users.io' # クラウドIDE
config.action_mailer.default_url_options = { host: host, protocol: 'https' }
一方、もしローカル環境で開発している場合は、次のようになります。
host = 'localhost:3000' # ローカル環境
config.action_mailer.default_url_options = { host: host, protocol: 'http' }
developmentサーバーを再起動して設定を読み込んだら、
次は自動生成したUserメイラーのプレビューファイルの更新が必要です
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
def account_activation
UserMailer.account_activation
end
# Preview this email at
# http://localhost:3000/rails/mailers/user_mailer/password_reset
def password_reset
UserMailer.password_reset
end
end
user変数が開発用データベースの最初のユーザーになるように定義して、それをUserMailer.account_activationの引数として渡します。
このとき、ではuser.activation_tokenの値にも代入している点にご注目ください。
テンプレートでは、アカウント有効化のトークンが必要なので、
代入は省略できません。
なお、activation_tokenは仮の属性でしかないので
データベースのユーザーはこの値を実際には持っていません。
アカウント有効化のプレビューメソッド (完成)
test/mailers/previews/user_mailer_preview.rb
# Preview all emails at http://3cfb3f48c6f540c799b69407f8f01afa.vfs.cloud9.ap-northeast-1.amazonaws.com0/rails/mailers/user_mailer class UserMailerPreview < ActionMailer::Preview # Preview this email at # http://3cfb3f48c6f540c799b6941afa.vfs.cloud9.ap-northeast-1.amazonaws.com/rails/mailers/user_mailer/account_activation def account_activation user = User.first user.activation_token = User.new_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
自分の場合クラウド9なので↓Preview Running appricationのホスト名を足す
http://3cfb3f.vfs.cloud9.ap-northeast-1.amazonaws.com/rails/mailers/user_mailer/password_reset
演習
1:Railsのプレビュー機能を使って、ブラウザから先ほどのメールを表示してみてください。「Date」の欄にはどんな内容が表示されているでしょうか?
Dateはブラウザでメールを表示した時点の日時が表示される。
11.2.3 送信メールのテスト
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
rails test:mailers
演習
この時点で、テストスイートが greenになっていることを確認してみましょう。
rails test:mailers
リスト 11.20で使ったCGI.escape
の部分を削除すると、テストが redに変わることを確認してみましょう。
CGI.escapeを削除してテスト
11.2.4 ユーザーのcreateアクションを更新
ユーザー登録にアカウント有効化を追加する red
app/controllers/users_controller.rb
class UsersController < ApplicationController . . . 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 else render 'new' end end . . . end
失敗するテストを一時的にコメントアウトする green
test/integration/users_signup_test.rb
require 'test_helper' class UsersSignupTest < ActionDispatch::IntegrationTest #中略 follow_redirect! # assert_template 'users/show' # assert is_logged_in? end end
演習
1:新しいユーザーを登録したとき、リダイレクト先が適切なURLに変わったことを確認してみましょう。その後、Railsサーバーのログから送信メールの内容を確認してみてください。有効化トークンの値はどうなっていますか?
https://ap-northeast-1.amazonaws.com/account_activations
/my8omJYTQnPJ41g/edit?email=boku%40example.com
2:コンソールを開き、データベース上にユーザーが作成されたことを確認してみましょう。また、このユーザーはデータベース上にはいますが、
有効化のステータスがfalseのままになっていることを確認してください。
rails cで確認する