Ruby Developer Notes Useful things

27Jul/106

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. Попробовал несколько альтернативных драйверов:

  1. gem sam-mysql-ruby - простой порт гема mysql под 1.9. Устанавливает кодировку строки как при чтении, так и при записи в БД.
  2. gem ruby-mysql - продвинутый драйвер с поддержкой кодировок. Устанавливает кодировки только при чтении. При записи в базу о кодировках надо думать самостоятельно.
  3. 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 больше не нужен. Все отлично работает и без него. Ура!

Comments (6) Trackbacks (0)
  1. Mysql2 нормально пишет в базу. Нужно только базу создать с нужным дефолтным чарсетом.

  2. Привет. Начал недавно изучать Rails 3 и столкнулся с теми же проблемами. Теперь изучаю тему локализации приложений. Есть наработки по данному вопросу?

  3. Да собственно после выхода релиза никаких проблем-то и нет.
    Для локализации мне вполне хватает возможностей I18n. Что конкретно Вас интересует?

  4. # coding: utf-8 – вот за это большое спасибо. Битый час терзал google пока не наткнулся на Ваш пост.

  5. Mysql2 нормально пишет в базу. Нужно только базу создать с нужным дефолтным чарсетом. – какой именно?

  6. interesnaya statya. Prodoljaite v tom je duhe!


Leave a comment

No trackbacks yet.