本文章所处环境为rails1.2.3,mysql 5,数据库编码使用utf8。
首先第一步请参照《
【转载】Rails使用gb2312/gbk与utf8共存的解决方案
》
第二步,修改web前端,在action执行前对params中的中文字符进行gbk转码。主要工作在app/controller/application.rb中。
代码:
Code
before_filter :encode_request_params
#
如果参数采用的是UTF8编码,则对参数进行GBK转码
def
encode_request_params
if
request.env[
"
HTTP_CONTENT_TYPE
"
]
=~/
UTF
-
8
/
encode_hash(params)
end
end
#
遍历params,将所有的字符串参数进行GBK转码
def
encode_hash(hash)
hash.each do
|
k,v
|
logger.info v.
class
if
v.instance_of? HashWithIndifferentAccess
encode_hash(v)
elsif v.instance_of? String
hash[k]
=
gbk(v)
end
end
hash
end
第三步,修改ActionView::Helpers::InstanceTag,改变to_input_field_tag方法输出input的默认行为。这里很奇怪的是,为什么使用value_before_type_cast方法呢?完全可以使用value方法啊。看过ActiveRecord中的实现,对string和text类型,type_cast操作也是一个空操作,没有做任何改变。
代码:
Code
class
ActionView::Helpers::InstanceTag
alias :original_to_input_field_tag :to_input_field_tag
def
to_input_field_tag(field_type, options
=
{})
options[
"
value
"
]
||=
value(object) unless field_type
==
"
file
"
original_to_input_field_tag(field_type, options)
end
end 第四步,修改ActiveRecord::Base和ActiveRecord::ConnectionAdapters::Column,在每次赋值和取值的时候自动进行编码转换。至于为什么这样做,请仔细研读相关代码,我也是费了好大劲才找到方案的。
代码:
Code
class
ActiveRecord::Base
alias :original_write_attribute :write_attribute
private
def
write_attribute(attr_name, value)
#
logger.info "write_attribute(#{attr_name}, #{value})"
if
text_column?(attr_name)
value
=
utf8(value)
#
logger.info "change value to #{value}"
end
original_write_attribute(attr_name, value)
end
public
def
text_column?(attr_name)
col
=
column_for_attribute(attr_name)
if
(!col.nil?
&&
(col.type
==
:string
||
col.type
==
:text))
true
else
false
end
end
end
class
ActiveRecord::ConnectionAdapters::Column
alias :original_type_cast_code :type_cast_code
def
type_cast_code(var_name)
case type
when :string then
"
gbk(#{var_name})
"
when :text then
"
gbk(#{var_name})
"
else
original_type_cast_code(var_name)
end
end
end 第五步,修改object基类,增加gbk和utf8两个方法。 可以看到,在第四步中的使用了gbk,utf8等方法,这些都是增加到object上的方法。
代码:
Code
class
Object
def
gbk(str)
if
str.blank?
''
elsif ! Kconv.isutf8(str)
str
else
Iconv.conv(
'
gb2312//IGNORE
'
,
'
utf-8//IGNORE
'
,str)
end
end
def
unicode_to_gbk(str)
Iconv.conv(
'
gb2312//IGNORE
'
,
'
unicode//IGNORE
'
,str)
end
#
将 GB2312 编码的字符串转换为 UTF-8 编码的字符串
def
utf8(str)
if
str.blank?
''
#
isutf8并不能很好来判定编码。比如“状态”这个词就会被误认为utf8
#
elsif Kconv.isutf8(str)
#
str
else
Iconv.conv(
'
utf-8//IGNORE
'
,
'
gb2312//IGNORE
'
,str)
end
end
end 这些代码放在哪里,怎么才能生效呢?我的做法是,编写一个或多个rb,放在lib中,然后在config/enviroments.rb文件的末尾使用require加载。
大功告成!