Обновление приложения 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 на ваших существующих данных.
Эта статья, кажется, освещает это довольно хорошо.
Надеюсь, это поможет!