営業職の俺がエンジニアになる

エンジニア経験がない私がエンジニアになるべく奮闘中

Railsで日本語メールを送る際のエラーを改修する

6月に入りRailsチュートリアルの2周目を進めている訳なのですが、2周目に入るにあたってSample Appの日本語化にチャレンジをしています。そんな中で、Railsチュートリアルを通常通りに進めている場合には起こり得ないエラーに遭遇したので共有をしたいと思います。このブログを書き始めて今回が初のTechブログ的な内容になります。(全くもってテッキーな内容じゃないです。すいません笑)

日本語のメールをテストする際のエラー

Railsチュートリアル11章でアカウント有効化のためにメールを送信する、という機能を実装します。チュートリアル上では作成するメールのテンプレートは全て英語で書かれています。今回、ここを日本語のメールテンプレートに書き換えた際に下記の様なエラーが発生しました。

user_mailer_test.rbのコード

test "account_activation" do
    user = users(:yuta)
    user.activation_token = User.new_token
    mail = UserMailer.account_activation(user)
    assert_equal "アカウント有効化", 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

エラーコード

 FAIL["test_account_activation", UserMailerTest, 1.2950874219823163]
 test_account_activation#UserMailerTest (1.30s)
        Expected /Yuta\ Toyokawa/ to match # encoding: US-ASCII
        "\r\n----==_mimepart_593cbb453f70e_acec4970f0255ce\r\nContent-Type: text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\nWXV0YSBUb3lva2F3YeanmAoK44KI44GG44GT44GdU2FtcGxlIEFwcOOBuO+8\r\ngeS4i+iomOOCouOCq+OCpuODs+ODiOacieWKueWMluODquODs+OCr+OCkuOC\r\nr+ODquODg+OCr+OBl+OBpuOBj+OBoOOBleOBhOOAggoKaHR0cDovL2V4YW1w\r\nbGUuY29tL2FjY291bnRfYWN0aXZhdGlvbnMvQnlXU0dubC1OVmJUQTJNUDd0\r\ncUgxQS9lZGl0P2VtYWlsPXl1dGElNDB0ZXN0LmNvbQo=\r\n\r\n----==_mimepart_593cbb453f70e_acec4970f0255ce\r\nContent-Type: text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding: base64\r\n\r\nPCFET0NUWVBFIGh0bWw+CjxodG1sPgogIDxoZWFkPgogICAgPG1ldGEgaHR0\r\ncC1lcXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNo\r\nYXJzZXQ9dXRmLTgiIC8+CiAgICA8c3R5bGU+CiAgICAgIC8qIEVtYWlsIHN0\r\neWxlcyBuZWVkIHRvIGJlIGlubGluZSAqLwogICAgPC9zdHlsZT4KICA8L2hl\r\nYWQ+CgogIDxib2R5PgogICAgPGgxPlNhbXBsZSBBcHA8L2gxPgoKPHA+WXV0\r\nYSBUb3lva2F3YeanmDwvcD4KCjxwPgrjgojjgYbjgZPjgZ1TYW1wbGUgQXBw\r\n44G477yB5LiL6KiY44Ki44Kr44Km44Oz44OI5pyJ5Yq55YyW44Oq44Oz44Kv\r\n44KS44Kv44Oq44OD44Kv44GX44Gm44GP44Gg44GV44GE44CCCjwvcD4KCjxh\r\nIGhyZWY9Imh0dHA6Ly9leGFtcGxlLmNvbS9hY2NvdW50X2FjdGl2YXRpb25z\r\nL0J5V1NHbmwtTlZiVEEyTVA3dHFIMUEvZWRpdD9lbWFpbD15dXRhJTQwdGVz\r\ndC5jb20iPuOCouOCq+OCpuODs+ODiOacieWKueWMljwvYT4KICA8L2JvZHk+\r\nCjwvaHRtbD4K\r\n\r\n----==_mimepart_593cbb453f70e_acec4970f0255ce--\r\n".
        test/mailers/user_mailer_test.rb:12:in `block in <class:UserMailerTest>'

要約すると、assert_matchで期待する値「Yuta Toyokawa」という値がメール本文(実際の値)にありません、という内容のようです。色々と調べてみましたが、日本語の文字コードの問題によるエラーのようでした。正直この原因を突き詰めるまでに大分時間を要しました。

解決策として有力候補に上がったのが「mail-iso-2022-jp」というメール本文の日本語をJISコードに書き換えてくれるgemファイルの導入でした。ということで、早速この「mail-iso-2022-jp」をgemファイルに追加し、インストールをすることに。

Gemfileへ「mail-iso-2022-jp」を導入

source 'https://rubygems.org'

gem 'rails',                   '5.0.0.1'
・
・
・
gem 'mail-iso-2022-jp'

group :development, :test do
・
・
・
$ bundle install

これで「mail-iso-2022-jp」を使う準備ができました。後は「application_mailer.rb」のコードを下記の通り書き換えるだけ。

application_mailer.rbへコードを追加

class ApplicationMailer < ActionMailer::Base
  default from: 'noreply@example.com', charset: 'ISO-2022-JP'
  layout 'mailer'
end

これで実際にテストが通過どうかを確認!意外と簡単にエラーを改修できた、、、っと思いきや次は、下記の様なエラーが、、

 FAIL["test_account_activation", UserMailerTest, 0.8312508999952115]
 test_account_activation#UserMailerTest (0.83s)
        --- expected
        +++ actual
        @@ -1 +1,2 @@
        -"アカウント有効化"
        +# encoding: ASCII-8BIT
        +"=?ISO-2022-JP?B?GyRCJSIlKyUmJXMlSE0tOHoyPRsoQg==?="
        test/mailers/user_mailer_test.rb:9:in `block in <class:UserMailerTest>'

どうやら「mail-iso-2022-jp」の仕様なのか、メールの件名である「mail.subject」が「ASCII-8BIT」にエンコードされてしまい、期待される値「アカウント有効化」と実際の値に差が出てしまうようです。実はこのエラー、私の今の力では解決ができず、色々と試してみてはいるのですが、結果としてパスをさせることができませんでした。

ただ、このテストをコメントアウトしてアカウント有効化の章を終わらせ、デプロイ後にメールの件名を確認してみたのですが、問題なく「アカウント有効化」という件名になっていたため、今は少しずるではありますが、コメントアウトのまま進めています。知識が溜まったタイミングで再度挑戦をしますが、一旦はRailsチュートリアル2周目を優先的に進めます。

ということで、少し煮え切らない形とはなりましたが、予期せぬえらーとの戦いにとりあえず終止符を打ちました。初めて技術系の内容を書いたので、書いてあることがめちゃくちゃかもしれませんが、ご容赦くださいませ。