4

During testing of ActionMailer I get the following error:

FAIL["test_account_activation", UserMailerTest, 2016-06-20 12:22:48
+0000]  test_account_activation#UserMailerTest (1466425368.07s)
        Expected /Michael\ Example/ to match # encoding: US-ASCII
        "\r\n----==_mimepart_5773e8f5616b_a8591b0e02475\r\nContent-Type:
text/plain;\r\n charset=UTF-8\r\nContent-Transfer-Encoding:
base64\r\n\r\n0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1IE1pY2hhZWwgRXhhbXBsZSwKCtCU\r\n0L7QsdGA0L4g0L/QvtC20LDQu9C+0LLQsNGC0YwhIArQn9C10YDQtdC50LTQ\r\nuNGC0LUg0L/QviDRg9C60LDQt9Cw0L3QvdC+0Lkg0L3QuNC20LUg0YHRgdGL\r\n0LvQutC1INC00LvRjyDQsNC60YLQuNCy0LDRhtC40Lgg0LLQsNGI0LXQuSDR\r\ng9GH0ZHRgtC90L7QuSDQt9Cw0L/QuNGB0Lg6CgpodHRwOi8vZXhhbXBsZS5j\r\nb20vYWNjb3VudF9hY3RpdmF0aW9ucy9VaGIzZ0lfbkd6clgxWEZkLWJackhn\r\nL2VkaXQ/ZW1haWw9bWljaGFlbCU0MGV4YW1wbGUuY29tCgoK\r\n\r\n----==_mimepart_5773e8f5616b_a8591b0e02475\r\nContent-Type:
text/html;\r\n charset=UTF-8\r\nContent-Transfer-Encoding:
base64\r\n\r\nPGh0bWw+CiAgPGJvZHk+CiAgICA8aDE+0JjQvdGB0YLRgNGD0LzQtdC90YLQ\r\nsNGA0LjQuSDQuNC90LbQtdC90LXRgNCwINC/0L4g0LrQsNGH0LXRgdGC0LLR\r\ngzwvaDE+Cgo8cD7Ql9C00YDQsNCy0YHRgtCy0YPQudGC0LUgTWljaGFlbCBF\r\neGFtcGxlLDwvcD4KCjxwPgrQlNC+0LHRgNC+INC/0L7QttCw0LvQvtCy0LDR\r\ngtGMISAK0J/QtdGA0LXQudC00LjRgtC1INC/0L4g0YPQutCw0LfQsNC90L3Q\r\nvtC5INC90LjQttC1INGB0YHRi9C70LrQtSDQtNC70Y8g0LDQutGC0LjQstCw\r\n0YbQuNC4INCy0LDRiNC10Lkg0YPRh9GR0YLQvdC+0Lkg0LfQsNC/0LjRgdC4\r\nOgo8L3A+Cgo8YSBocmVmPSJodHRwOi8vZXhhbXBsZS5jb20vYWNjb3VudF9h\r\nY3RpdmF0aW9ucy9VaGIzZ0lfbkd6clgxWEZkLWJackhnL2VkaXQ/ZW1haWw9\r\nbWljaGFlbCU0MGV4YW1wbGUuY29tIj7QkNC60YLQuNCy0LjRgNC+0LLQsNGC\r\n0Yw8L2E+CgoKICA8L2JvZHk+CjwvaHRtbD4K\r\n\r\n----==_mimepart_5773e8f5616b_a8591b0e02475--\r\n".
        test/mailers/user_mailer_test.rb:13:in `block in <class:UserMailerTest>'

This error happens only if I use Russian text inside account_activation.text.erb view, so I guess this is related to encoding. (Everything is ok if I use English). Moreover, the strange thing is that Russian inside html view (account_activation.html.erb ) passes without fail.

Your suggestions how to solve this would be highly appreciated.

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 "Активация учётной записи", mail.subject
    #assert_equal "Activate", mail.subject
    assert_equal [user.email], mail.to
    assert_equal ["noreply@QET.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

user_mailer.rb:

class UserMailer < ApplicationMailer
  def account_activation(user)
    @user = user
    mail to: user.email, subject: "Активация учётной записи"
  end
end

fixtures/users.yml:

michael:
  name: Michael Example
  email: michael@example.com
  password_digest: <%= User.digest('password') %>
  tenant: company1
  admin: true
  activated: true
  activated_at: <%= Time.zone.now %>

account_activation.text.erb:

Здравствуйте <%= @user.name %>,

Добро пожаловать! 
Перейдите по указанной ниже ссылке для активации вашей учётной записи:

<%= edit_account_activation_url(@user.activation_token, email: @user.email) %>
Mark Booth
  • 7,605
  • 2
  • 68
  • 92
Dmitri
  • 43
  • 6

3 Answers3

2

As this mail is multipart, try to get message body directly from text_part method, convert it to string and encode to UTF-8 as usual. In your case:

assert_match user.name,               mail.text_part.body.to_s.encode("UTF-8")
assert_match user.activation_token,   mail.text_part.body.to_s.encode("UTF-8")
assert_match CGI.escape(user.email),  mail.text_part.body.to_s.encode("UTF-8")
Alex T.
  • 141
  • 1
  • 13
0

It seems the reason for the issue is comparing the strings in different encodings. There is a mention of US-ASCII and UTF-8 in your log and the difference may come from the encodings of the source files.

Ruby prior to 2.0 required explicitly defining source file encoding if different from the environment. This is done with a comment at the top of the source file:

# encoding: utf-8

To add the directive to an erb template, do this:

<%# encoding: utf-8 -%>

Ruby versions from 2.0 up treat all source files as utf-8 encoded by default. For more details see this answer.

Another solution would be to configure ActionMailer to use a specific encoding:

config.action_mailer.default charset: 'utf-8'

As this is an ActionMailer default, just make sure it is not changed in config/environments/test.rb.

Community
  • 1
  • 1
Nic Nilov
  • 5,056
  • 2
  • 22
  • 37
  • Thank you for a suggestion. Unfortunately, this doesn't work in Rails 4 in text.erb views. – Dmitri Jun 29 '16 at 17:41
  • You don't have to fix your `erb` template. As you pointed out the html is rendered fine. It's either your `user_mailer.rb` or `user_mailer_test.rb`. – Nic Nilov Jun 29 '16 at 17:47
  • Specifying `config.action_mailer.default charset: 'utf-8'` in test.rb doesn't help. I don't explicitly change encoding anywhere in my code. – Dmitri Jun 29 '16 at 20:28
  • Have you still tried to add the encoding directive to your `.text.erb` template? It is clearly seen in the log it gets picked up in an ASCII encoding: `US-ASCII "\r\n----==_mimepart_5773e8f5616b_a8591b0e02475\r\nContent-Type: text/plain;`. I think I was wrong stating that it doesn't need fixing. – Nic Nilov Jun 29 '16 at 20:41
  • Yes I tried this without success. Adding this directive to fixtures and to user_mailer_test.rb also doesn't work. – Dmitri Jul 01 '16 at 09:23
  • Try to manually set encoding on your russian strings in both template and test, e.g. 'text'.force_encoding ('UTF-8') – Nic Nilov Jul 01 '16 at 09:27
  • Changing to `assert_match user.name.force_encoding('UTF-8'), mail.body.encoded` in test doesn't change anything. Also changing text in view to `<%= 'Добро пожаловать'.force_encoding('UTF-8') %>` doesn't help. I guess the problem comes from how `mail.body.encoded` or `assert_match` is interpreting unicode text... – Dmitri Jul 01 '16 at 14:10
0

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

to

    
    assert_match user.name,              mail.text_part.body.encoded
    assert_match user.name,               mail.html_part.body.encoded
    
    assert_match user.activation_token,   mail.text_part.body.encoded
    assert_match user.activation_token,   mail.html_part.body.encoded
    assert_match CGI.escape(user.email),  mail.text_part.body.encoded
    assert_match CGI.escape(user.email),  mail.html_part.body.encoded

I quoted from: https://rakuda3desu.net/rakudas-rails-tutorial11-2/