环境:
os: ubuntu 10.04
ruby: 1.9.2
rails: rails3
server: webrick/nginx+passenger/thin
把以前程序拿来跑的时候无意间发现ruby也有中文问题啊!
理论上说字符编码都是UTF-8的,不应该有问题,至少在java里就不会有问题。为什么在ruby就有问题呢?
ruby1.9才开始支持unicode,以前是专门在日本用的,如果直接使用unicode,据说对有些日文的支持不理想。这的确是一件让人郁闷的事。
即便到了1.9也没是全用unicode,ruby搞了个m17n的东西,对国际化的支持算是不错了,但很多类库还是使用的ascii-8这东西,因此就会出现:
引用
incompatible character encodings: ASCII-8BIT and UTF-8
google了一下,网上的解决方式很多,但大多都不可行,有部分没试过。
http://www.iteye.com/topic/355909
这篇文章提了两点,一是改模板的编码,试了一下没有效果。仔细看了下代码,应该说组装的时候用的是ASCII-8BIT,但输出的时候还是UTF-8的格式,说明这个地方没有问题。
更加可以确认这地方没有问题的是,在application.rb里面有代码:
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
第二点是说mysql gem的问题,经过验证这里确实有问题。这个过程是,首先从数据库查询出数据来,而这种数据的格式为ASCII-8BIT,如果model类里面有中文数据,那么这种数据肯定是utf8的,混在一起就会出现不兼容的字节编码。如果没有,那么这个ASCII-8BIT会受到统一的处理,以utf-8的方式显示,因此中文能正常显示。如果把model类的中文改为ASCII-8BIT编码方式,那么在创建model页面如果有中文,那么那个页面必须是utf8的格式,而model类有ascii8的数据,所以也会出现编码不兼容。
所以最好的方式是修改返回数据的编码方式,这一点,那篇文章讲得很对,只是现在那个文件已经不叫那个名字了。位置:/ruby/lib/ruby/gems/1.9.1/gems/activerecord-3.0.0.rc/lib/rails/generators/active_record/mysql_adapter.rb
照着那篇文章的改就可以了,改后为:
..
def select(sql, name = nil)
@connection.query_with_result = true
result = execute(sql, name)
rows = []
result.each_hash { |row| rows << row }
result.free
rows
if @config[:encoding] && @config[:encoding]=="utf8"
rows.each do |row|
row.each do |key, value|
if (value.class == String)
value.force_encoding("UTF-8")
end
end
end
end
end
..
这样数据库输出的格式就是utf8的,就算model类有中文也不怕了。
顺便说一下,在model类或controller中如果要使用了中文字符,最好在类前面加上魔法注释:
# coding: utf-8
不然很多服务器上跑都有问题。
不过比较奇怪的是,在原来的windows中,187+rails3rc+mongrel没有这些中文问题,一切正常,连魔法注释也不用加,mysql gem也是2.8.1的。
后记(2010.8.31),今天rails3正式版出来了,试了一下这个问题还是没解决。其实这主要是mysql gem 的问题,rails能起的作用不大。忽然记得以前rails3rc发布的时候有句支持mysql2 gem的话,于是在网上搜了一下,果然有这个东西,而且性能与编码支持都做得很好。
既然这样,没有理由不去试一下。
1.安装mysql2: sudo gem install mysql2
2.修改Gemfile:
#gem 'mysql', '2.8.1'
gem "mysql2", "0.2.3"
3.修改database.yml:
引用
adapter: mysql2
.....
password: '123456'
注意,如果密码为数字,则需要用字符串的形式,否则出报错。如果ruby文件中有中文,那么还是要把魔法注释加上,至少在本人目前使用的ubuntu+nginx+passenger中是这样的。
经过上面步骤以后,运行以前的代码,中文问题彻底的得到解决。