はじめに
Ruby on Rails チュートリアル実例を使ってRailsを学ぼう 第4版の 12章 12.2 パスワード再設定のメール送信の演習まとめ&回答例です。
個人の解答例なので、誤りがあればご指摘ください。
動作環境
- cloud9
- ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-linux]
- Rails 5.0.0.1
12.2.1 パスワード再設定のメールとテンプレート
本章での学び
【Mailer】Userメイラーの実装
自動生成されたメール送信処理のメソッドpassword_reset
の中身を実装する。
# Subject can be set in your I18n file at config/locales/en.yml # with the following lookup: # # en.user_mailer.password_reset.subject # def password_reset @greeting = "Hi" mail to: "to@example.org" end
上記のコードは削除して、下記の通り編集する。
def password_reset(user) @user = user mail to: user.email, subject: "Password reset" end
【Mailer】メールテンプレートの実装
自動生成されているtextメールのテンプレートの中身を実装する。
To reset your password click the link below: <%= edit_password_reset_url(@user.reset_token, email: @user.email) %> This link will expire in tow hours. If you did not request your password to be reset, please ignore this email and your password will stay as it is.
自動生成されているhtmlメールのテンプレートの中身を実装する。
<h1>Password reset</h1> <p>To reset your password click the link below:</p> <%= link_to "Reset password", edit_password_reset_url(@user.reset_token, email: @user.email) %> <p>This link will expire in two hours.</p> <p> If you did not request your password to be reset, please ignore this email and your password will stay as it is. </p>
【Mailer】プレビュー処理の実装
自動生成されたプレビュー処理の中身を実装する。
# Preview this email at http://localhost:3000/rails/mailers/user_mailer/password_reset def password_reset UserMailer.password_reset end
上記のコードを削除して、下記のとおり実装する。
def password_reset user = User.first user.reset_token = User.new_token UserMailer.password_reset(user) end
動作確認前の注意点
本項目の実行環境は、developであるため、実際にメールは送信されない。 (production環境でなければ、実際にメールは飛ばない) 私はdevelop環境であることを失念していたので、メールが飛ばないのはなぜかと、小一時間悩みました。。。
プレビュー処理の動作確認
下記のURLにアクセスして動作確認を行う。 https://xxxxxxx/rails/mailers/user_mailer/password_reset
textメールのプレビューができることを確認。
htmlメールのプレビューができることを確認。
パスワード再設定メール送信処理の動作確認
ブラウザを起動し、有効なメールアドレスを入力して、パスワード再設定メールを送信する。 動作確認のためのメールアドレスは、10分メールアドレスを使うと便利。
ブラウザ上で、パスワード再送信メールが送信できたメッセージが表示されたことを確認。
コンソールログの確認
入力したメールアドレス宛に、パスワード再設定メールが送信されていることを確認。
Sent mail to hsa09793@tqosi.com (8.3ms) Date: Sun, 09 Jul 2017 01:24:46 +0000 From: noreply@example.com To: hsa09793@tqosi.com Message-ID: <596185de75f24_dcf20b491898558@yokoyan-rails-tutorial-4550834.mail> Subject: Password reset Mime-Version: 1.0 Content-Type: multipart/alternative; boundary="--==_mimepart_596185de74823_dcf20b491898458"; charset=UTF-8 Content-Transfer-Encoding: 7bit ----==_mimepart_596185de74823_dcf20b491898458 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit To reset your password click the link below: https://rails-tutorial-yokoyan.c9users.io/password_resets/UDO5Wja1Uh_eiltpVaPxpw/edit?email=hsa09793%40tqosi.com This link will expire in tow hours. If you did not request your password to be reset, please ignore this email and your password will stay as it is. ----==_mimepart_596185de74823_dcf20b491898458 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 7bit <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style> /* Email styles need to be inline */ </style> </head> <body> <h1>Password reset</h1> <p>To reset your password click the link below:</p> <a href="https://rails-tutorial-yokoyan.c9users.io/password_resets/UDO5Wja1Uh_eiltpVaPxpw/edit?email=hsa09793%40tqosi.com">Reset password</a> <p>This link will expire in two hours.</p> <p> If you did not request your password to be reset, please ignore this email and your password will stay as it is. </p> </body> </html>
演習1
ブラウザから、送信メールのプレビューをしてみましょう。「Date」の欄にはどんな情報が表示されているでしょうか?
UTC時間が表示される。 日本時間から9時間ずれて表示される。
演習2
パスワード再設定フォームから有効なメールアドレスを送信してみましょう。また、Railsサーバーのログを見て、生成された送信メールの内容を確認してみてください。
前述の「コンソールログの確認」参照。
演習3
コンソールに移り、先ほどの演習課題でパスワード再設定をしたUserオブジェクトを探してください。オブジェクトを見つけたら、そのオブジェクトが持つreset_digestとreset_sent_atの値を確認してみましょう。
演習2で使用したユーザーのメールアドレスで検索。
reset_digest
と、reset_sent_at
に値が入っていることを確認。
yokoyan:~/workspace/sample_app (password-reset) $ rails console --sandbox Running via Spring preloader in process 3587 Loading development environment in sandbox (Rails 5.0.0.1) Any modifications you make will be rolled back on exit >> ?> user = User.find_by(email: "hsa09793@tqosi.com") User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", "hsa09793@tqosi.com"], ["LIMIT", 1]] => #<User id: 103, name: "mail_test", email: "hsa09793@tqosi.com", created_at: "2017-07-09 01:06:40", updated_at: "2017-07-09 01:24:46", password_digest: "$2a$10$F42JIypvQYXBt6V2pe7A4ONXQ4PImXqR0GSK7ioCrj5...", remember_digest: nil, admin: false, activation_digest: "$2a$10$V4Z1Rgva0TA.FJqv7/SWAO/vfjX0sBSpgLpKjx8itK7...", activated: nil, activated_at: nil, reset_digest: "$2a$10$dsfjyWCpuX.9I4c7zbWYieBp4nxc.fzipFaYHyaHcP8...", reset_sent_at: "2017-07-09 01:24:46"> >> ?> user.reset_digest => "$2a$10$dsfjyWCpuX.9I4c7zbWYieBp4nxc.fzipFaYHyaHcP83yMQRBtFaO" >> ?> user.reset_sent_at => Sun, 09 Jul 2017 01:24:46 UTC +00:00
12.2.2 送信メールのテスト
本章での学び
【test】パスワード再設定用メイラーメソッドのテストを作成
11章でコメントアウトしていたテストコードを実装する。
- michaelユーザの情報を取得
- パスワード再設定トークンを生成
- パスワード再設定メールを送信
- メールオブジェクトの件名に、"Password reset"が含まれているかチェック
- メールオブジェクトの宛先が、ユーザのemailと一致しているかチェック
- メールオブジェクトのfromアドレスが、
noreply@example.com
と一致しているかチェック - テストユーザのパスワード再設定トークンが、エンコードされたメール本文内に存在するかチェック
- テストユーザのアドレスがエスケープされて、エンコードされたメール本文に含まれているかチェックする
上記を踏まえて実装する。
test "password_reset" do user = users(:michael) user.reset_token = User.new_token mail = UserMailer.password_reset(user) assert_equal "Password reset", mail.subject assert_equal [user.email], mail.to assert_equal ["noreply@example.com"], mail.from assert_match user.reset_token, mail.body.encoded assert_match CGI.escape(user.email), mail.body.encoded end
動作確認
テストコードがgreenになることを確認。
yokoyan:~/workspace/sample_app (password-reset) $ rails test Running via Spring preloader in process 5896 Started with run options --seed 1346 47/47: [===================================================================================================] 100% Time: 00:00:02, Time: 00:00:02 Finished in 2.88912s 47 tests, 205 assertions, 0 failures, 0 errors, 0 skips
演習1
メイラーのテストだけを実行してみてください。このテストは greenになっているでしょうか?
メイラーのテストだけ実行する。
rails test test/ディレクトリ名/ファイル名
greenになることを確認。
yokoyan:~/workspace/sample_app (password-reset) $ rails test test/mailers/user_mailer_test.rb Running via Spring preloader in process 6095 Started with run options --seed 2562 2/2: [=====================================================================================================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.67604s 2 tests, 16 assertions, 0 failures, 0 errors, 0 skips
演習2
リスト 12.12にある2つ目のCGI.escapeを削除すると、テストが redになることを確認してみましょう。
エスケープ処理をコメントアウトする。
# assert_match CGI.escape(user.email), mail.body.encoded assert_match user.email, mail.body.encoded
テストがredになることを確認。
yokoyan:~/workspace/sample_app (password-reset) $ rails test test/mailers/user_mailer_test.rb Running via Spring preloader in process 6187 Started with run options --seed 5175 FAIL["test_password_reset", UserMailerTest, 0.6262194160372019] test_password_reset#UserMailerTest (0.63s) Expected /michael@example\.com/ to match # encoding: US-ASCII "\r\n----==_mimepart_596197d92db13_182bcc70e015864\r\nContent-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\nTo reset your password click the link below:\r\n\r\nhttp://example.com/password_resets/IWAHQV67Gyu6BAQUaz9OoA/edit?email=michael%40example.com\r\n\r\nThis link will expire in tow hours.\r\n\r\nIf you did not request your password to be reset, please ignore this email and your password will stay as it is.\r\n\r\n\r\n----==_mimepart_596197d92db13_182bcc70e015864\r\nContent-Type: text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: 7bit\r\n\r\n<!DOCTYPE html>\r\n<html>\r\n <head>\r\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\r\n <style>\r\n /* Email styles need to be inline */\r\n </style>\r\n </head>\r\n\r\n <body>\r\n <h1>Password reset</h1>\r\n\r\n<p>To reset your password click the link below:</p>\r\n\r\n<a href=\"http://example.com/password_resets/IWAHQV67Gyu6BAQUaz9OoA/edit?email=michael%40example.com\">Reset password</a>\r\n\r\n<p>This link will expire in two hours.</p>\r\n\r\n<p>\r\n If you did not request your password to be reset, please ignore this email and your password will stay as it is.\r\n</p>\r\n\r\n </body>\r\n</html>\r\n\r\n----==_mimepart_596197d92db13_182bcc70e015864--\r\n". test/mailers/user_mailer_test.rb:25:in `block in <class:UserMailerTest>' 2/2: [=====================================================================================================] 100% Time: 00:00:00, Time: 00:00:00 Finished in 0.63150s 2 tests, 16 assertions, 1 failures, 0 errors, 0 skips
テスト実行後は元に戻しておく。
おわりに
パスワード再設定メールの総身諸利を実装することができました。 まだ、production環境にデプロイしていないため、実際にパスワード再設定メールが飛ぶかどうかの確認ができていません。(ここは、12.4 本番環境でのメール送信 (再掲)で実施) 今回、develop環境でメールが飛ばないことを失念しており、はまってしまったのでみなさんもご注意ください。。。