Ruby 1.9, Rails и invalid byte sequence in US-ASCII

24 ноября 2011, 00:54
Готов поспорить, если у вас есть legacy-проект на Rails 2.3, в котором до сих пор используется версия ruby 1.8.7, то не раз была попытка перехода на 1.9, в погоне за новыми возможностями и ускорением работы приложения :)
И раз проект все еще на 1.8.7..
Обычно, проблемы возникают с кодировками: русскими текстами, записанными в .erb, или строками на русском языке, возвращаемыми из MySQL.

Возникающие ошибки проявляются в виде сообщений типа:
invalid byte sequence in US-ASCII
или:
incompatible character encodings: UTF-8 and ASCII-8BIT.

В Интернете довольно много разношерстных решений данной проблемы. Попытаюсь собрать их в одном месте.

environment.rb

В самое начало необходимо вставить такие строчки кода:
Encoding.default_internal = Encoding::UTF_8
Encoding.default_external = Encoding::UTF_8
Подробнее можно почитать по этой ссылке: http://blog.grayproductions.net/articles/ruby_19s_three_default_encodings. Там объясняется смысл этих строк.

config/initializers/patches.rb

# Patching MySQL:
#
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

# Patching ActionController:
#
module ActionController
class Request
private
def normalize_parameters_with_force_encoding(value)
(_value = normalize_parameters_without_force_encoding(value)).respond_to?(:force_encoding) ?
_value.force_encoding(Encoding::UTF_8) : _value
end
alias_method_chain :normalize_parameters, :force_encoding
end
end
Данный код делает примерно то же самое, но специально для MySQL и ActionController.
Эти способы нашим проектам - помогли. Надеюсь и вашим тоже :) Удачи!