ActionView:: Template:: Error (несовместимые кодировки символов: UTF-8 и ASCII-8BIT)

Я использую Ruby 1.9.2, Rails 3.0.4/3.0.5 и Phusion Passenger 3.0.3/3.0.4. Мои шаблоны написаны в HAML, и я использую жемчужину MySQL2. У меня есть действие контроллера, которое при передаче параметра, имеющего специальный символ, например умлаут, вызывает следующую ошибку:

ActionView::Template::Error (incompatible character encodings: UTF-8 and ASCII-8BIT)

Ошибка указывает на первую строку моего шаблона HAML, на которой есть следующий код:

<!DOCTYPE html>

Я понимаю, что это вызвано тем, что у меня есть строка UTF-8, которая конкатенируется с строкой ASCII-8BIT, но я не могу на всю жизнь понять, что это за строка ASCII-8BIT. Я проверил, что параметры в действии закодированы с использованием UTF-8, и я добавил кодировку: декларация UTF-8 в начало шаблона HAML и файлы ruby, и я до сих пор получаю эту ошибку. В моем файле application.rb также есть объявление config.encoding = "UTF-8", а в UTF-8 следующее:

ENV['LANG']
__ENCODING__
Encoding.default_internal
Encoding.default_external

Здесь кикер: я не могу воспроизвести этот результат локально на моем Mac OSX, используя автономный пассажир или дворняжку в разработке или производстве. Я могу воспроизвести его только на рабочем сервере, на котором работает nginx + пассажир на linux. Я проверил в консоли сервера производства, что последние упомянутые команды все также приводят к UTF-8.

У вас возникла такая же ошибка и как вы ее разрешили?

Ответы

Ответ 1

После выполнения некоторой отладки я обнаружил, что проблема возникает при использовании объекта ActionDispatch:: Request, который имеет целые строки, все кодированные в ASCII-8BIT, независимо от того, закодировано ли мое приложение в UTF-8 или нет. Я не знаю, почему это происходит только при использовании производственного сервера в Linux, но я собираюсь взять на себя некоторые причуды в Ruby или Rails, так как я не смог воспроизвести эту ошибку локально. Ошибка произошла именно из-за такой строки:

@current_path = request.env['PATH_INFO']

Когда эта переменная экземпляра была напечатана в шаблоне HAML, она вызвала ошибку, потому что строка была закодирована в ASCII-8BIT вместо UTF-8. Чтобы решить эту проблему, я сделал следующее:

@current_path = request.env['PATH_INFO'].dup.force_encoding(Encoding::UTF_8)

Какой принудительный @current_path использовать дублируемую строку, которая была принудительно введена в правильную кодировку UTF-8. Эта ошибка также может возникать с другими данными, связанными с запросом типа request.headers.

Ответ 2

Mysql может быть источником проблемных ascii. Попытайтесь поместить в инициализатор, чтобы как минимум устранить эту возможность:

require 'mysql'

class Mysql::Result
  def encode(value, encoding = "utf-8")
    String === value ? value.force_encoding(encoding) : value
  end

  def each_utf8(&block)
    each_orig do |row|
      yield row.map {|col| encode(col) }
    end
  end
  alias each_orig each
  alias each each_utf8

  def each_hash_utf8(&block)
    each_hash_orig do |row|
      row.each {|k, v| row[k] = encode(v) }
      yield(row)
    end
  end
  alias each_hash_orig each_hash
  alias each_hash each_hash_utf8
end



изменить

Это может быть неприменимо к gem mysql2. Однако работает для mysql.