Rails 3 + Ruby 1.9 = борьба с кодировками
Посвящается Rails 3.0.0.rc
Недавно пробовал покатать Rails EDGE на Ruby 1.9.2-head и конечно же нарвался на проблему с кодировками. Однако их оказалось не так много как я предполагал.
Для начала надо убедиться что в файле config/application.rb прописано config.encoding = "utf-8". Это позволяет сэкономить нервы с кодировкой шаблонов. Но именно шаблонов, для моделей и контроллеров надо указывать специальный комментарий вначале файла:
[cc lang="ruby"]
# coding: utf-8
[/cc]
Первое с чем пришлось столкнуться - драйвер MySQL (gem mysql) не выставляет кодировки у строк и Ruby 1.9 воспринимает эту строку как ASCII-8BIT. Попробовал несколько альтернативных драйверов:
- gem sam-mysql-ruby - простой порт гема mysql под 1.9. Устанавливает кодировку строки как при чтении, так и при записи в БД.
- gem ruby-mysql - продвинутый драйвер с поддержкой кодировок. Устанавливает кодировки только при чтении. При записи в базу о кодировках надо думать самостоятельно.
- gem mysql2 - альтернативный драйвер с поддержкой кодировок строки в ruby 1.9. Устанавливает кодировки только при чтении. При записи в базу о кодировках надо думать самостоятельно.
Если возникли проблемы с компиляцией, то обычно помогает примерно следующее:
[cc lang="bash" width="700"]
gem install sam-mysql-ruby -- --with-mysql-config=/opt/local/bin/mysql_config5
[/cc]
Я остановился на втором варианте. Поскольку решение следующей проблемы устранило его недостаток.
Далее возникла проблема с кодировкой данных приходящих от пользователя. При возникновении ошибки валидации данных во время сабмита формы вылетало исключение о несовместимости кодировок:
incompatible character encodings: ASCII-8BIT and UTF-8
Проблема оказалась в том, что кодировка пустой строки остается ASCII-8BIT. Пришлось найти middleware patch, который явно устанавливает кодировку данных пришедших из формы:
[cc lang="ruby" width="700"]
if RUBY_VERSION < '1.9'
module Fx
class UnicodeEnforcer
def initialize(app)
@app = app
end
def call(env)
req = Rack::Request.new(env)
force_encoding(req.params)
@app.call(env)
end
def force_encoding(on)
case on
when String
on.dup.force_encoding('utf-8')
when Array
on.map(&method(:force_encoding))
when Hash
on.each_pair do | k, v |
on[k] = force_encoding(v)
end
else
on
end
end
end
end
Appname::Application.config.middleware.use Fx::UnicodeEnforcer
end
[/cc]
Добавляем его в config/initializers/ruby19.rb и наслаждаемся!
Пока больше проблем не замечено. Так что эта связка вполне работоспособна. Однако в продакшене пока не пробовал - лень настраивать сервер. Heroku - наше всё! 🙂
Третьими рельсами очень даволен, многие архитектурные решения сильно радуют. Стабильность работы меня пока тоже не огорчила. Так что горячо рекомендую.
P.S.
Только что проверил - middleware patch больше не нужен. Все отлично работает и без него. Ура!
July 28th, 2010 - 08:32
Mysql2 нормально пишет в базу. Нужно только базу создать с нужным дефолтным чарсетом.
August 30th, 2010 - 00:33
Привет. Начал недавно изучать Rails 3 и столкнулся с теми же проблемами. Теперь изучаю тему локализации приложений. Есть наработки по данному вопросу?
August 30th, 2010 - 13:27
Да собственно после выхода релиза никаких проблем-то и нет.
Для локализации мне вполне хватает возможностей I18n. Что конкретно Вас интересует?
March 31st, 2011 - 19:34
# coding: utf-8 – вот за это большое спасибо. Битый час терзал google пока не наткнулся на Ваш пост.
June 3rd, 2011 - 17:06
Mysql2 нормально пишет в базу. Нужно только базу создать с нужным дефолтным чарсетом. – какой именно?
September 22nd, 2018 - 14:46
interesnaya statya. Prodoljaite v tom je duhe!