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.