Обновление приложения Rails 3 с Ruby 1.8.7 до 1.9.3 перестает уважать спецификацию кодировки latin1 в database.yml

Я обновляю приложение Rails 3.2.13 с Ruby 1.8.7-p370 до Ruby 1.9.3-p385. После обновления специальные символы искажаются в тексте, полученном из базы данных. Например, "кафе" выглядит как "кафе". Моя база данных имеет латинский код. Я использую mysql2 (0.3.11) и мой database.yml выглядит так:

development:
  adapter: mysql2
  encoding: latin1
  database: my_db
  username: root
  host: localhost

(Та же самая проблема также происходит в производственной среде, которая имеет ту же конфигурацию базы данных.)

Похоже, что когда ActiveRecord извлекает текст из базы данных, он декодирует его, как если бы это был utf-8, а не latin1 (или ISO-8859-1), как я указал.

Чтобы диагностировать проблему, я написал скрипт на Ruby, который использует mysql2 для прямого запроса к базе данных, минуя ActiveRecord:

require 'rubygems'
require 'mysql2'

client = Mysql2::Client.new(:host => "localhost",
                            :username => "root",
                            :database => "food52_development_production",
                            :encoding => "latin1")

result = client.query('SELECT title FROM recipes WHERE id = 12934')

puts result.first["title"]

Рецепт с идентификатором 12934 имеет в своем названии слово "кафе". При запуске этого скрипта в 1.9.3 выводится правильно декодированный текст ("café"). Если я изменю :encoding возможность "utf-8"Я еще раз вижу искаженный текст ("Кафе").

Я также попытался установить точку останова в ActiveRecord::ConnectionAdapters, чтобы увидеть, как конфигурация Rails инициализировала Mysql2::Client с. Это передается :encoding => "latin1", как и ожидалось.

И все же: где-то вдоль линии Rails решает декодировать текст как utf-8. Как мне заставить Rails соблюдать указанную мной конфигурацию кодировки latin1? Заранее спасибо за помощь.

1 ответ

Начиная с 1.9.3, iconv устарела. Кроме того, Rails 3 ожидает кодирование UTF-8 на всех входах.

С учетом сказанного, у вас есть пара разных вариантов. Во-первых, это довольно странно, но если вы не хотите переносить данные, это сработает.

Библиотека iconv по-прежнему доступна в виде гема, который вы можете использовать для ручного выполнения этих преобразований, когда это необходимо в вашем приложении.

Ребята из Airbnb используют такого помощника:

def self.convert_string_encoding(to, from, str)
  if "1.9".respond_to?(:force_encoding)
    str = str.dup if str.frozen?
    str.encode(to, from, :undef => :replace)
  else
    require 'iconv'
    Iconv.conv(to, from, str)
  end
end

обрабатывать преобразования. Вы могли бы потенциально добавить это в качестве помощника для ваших взглядов.

Вы можете прочитать больше об их миграции здесь

Проблема будет в том, что когда вы попытаетесь преобразовать UTF-8 по умолчанию для rails обратно в вашу базу данных.

Что, вероятно, имеет больше смысла, так это выполнить миграцию в UTF-8 на ваших существующих данных.

Эта статья, кажется, освещает это довольно хорошо.

Надеюсь, это поможет!

Другие вопросы по тегам