本文章所处环境为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加载。
大功告成!