将Rails 3应用程序从Ruby 1.8.7升级到1.9.3会停止遵守database.yml中的latin1编码规范

时间:2013-03-20 16:10:45

标签: ruby-on-rails-3 character-encoding ruby-1.9 mysql2 latin1

我正在将Rails 3.2.13应用程序从Ruby 1.8.7-p370升级到Ruby 1.9.3-p385。升级后,从数据库中检索的文本中的特殊字符会出现乱码。例如,“café”显示为“café”。我的数据库是latin1编码的。我正在使用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"]

id为12934的食谱标题中包含“café”字样。在1.9.3中运行此脚本会输出正确解码的文本(“café”)。如果我将:encoding选项更改为"utf-8",我会再次看到乱码文本(“café”)。

我还尝试在ActiveRecord::ConnectionAdapters中放置断点,以查看Rails正在初始化Mysql2::Client的编码配置。它按预期传递:encoding => "latin1"

然而:在某个地方,Rails决定将文本解码为utf-8。如何让Rails尊重我指定的latin1编码配置?在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

从1.9.3开始,不推荐使用iconv。此外,Rails 3期望在所有输入上使用UTF-8编码。

话虽如此,你有几个不同的选择。第一个是非常hacky,但是如果你不想迁移你的数据,它将会起作用。

iconv库仍以gem形式提供,您应该可以在应用中手动执行这些转换。

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

处理转化。您可以将其放在帮助视图中。

您可以详细了解他们的迁移here

问题在于尝试将rails的默认UTF-8转换回数据库的编码。

可能更有意义的是在现有数据上迁移到UTF-8。

This article seems to cover that fairly well.

我希望这有帮助!