素不相识!
在一个在Rails 2.3.8中完美运行的应用程序中,我有以下类方法:
def self.encode(*attr_names)
encoder = Encoder.new(attr_names)
before_save encoder
after_save encoder
after_find encoder
define_method(:after_find) { } # defining here, since there's only alias in the Encoder class itself
end
此方法引用Encoder类。这是它:
class Encoder
include Encodings
def initialize(attrs_to_manage) # We're passed a list of attributes that should be stored encoded in the database
@attrs_to_manage = attrs_to_manage
end
def before_save(model) # Before saving or updating, encode the attributes to their original encoding
@attrs_to_manage.each do |field|
model[field] = to_orig_encod(model[field])
end
end
def after_save(model) # After saving, encode them back to utf8
@attrs_to_manage.each do |field|
model[field] = to_utf8(model[field])
end
end
alias_method :after_find, :after_save # Do the same after finding an existing record
end
在升级到rails3之前,所有回调(before_save,after_save,after_find)都运行正常。升级后 before_save 和 after_save 仍然有效,但 after_find 没有,我在日志中收到以下弃用警告:
DEPRECATION WARNING: Base#after_find has been deprecated, please use Base.after_find :method instead
我不确定如何更改我的代码以重新启用after_find回调的功能。我尝试了一些简单的替换但没有成功,这个回调的rails API文档非常有限,没有实现的例子。
任何帮助表示感谢,提前谢谢!
修改
以下是解决方案:
好的,所以似乎问题比最初出现的问题更微妙。经过额外的测试后,我发现事实上,正如Jeppe指出的那样,无论弃用警告如何,after_find回调都能正常工作,“to_utf8”方法实际上是对模型属性进行了卓越的调用和执行。结果与期望不符的原因是“to_utf8”方法本身。它的作用是使用ruby模块Iconv将字符串从非utf8编码转换为例如cp1251到utf。这是针对从具有非utf编码的远程遗留数据库使用Active Record获取的模型的属性完成的。然而,事实证明,与以前版本的rails不同,rails 3 中的AR自动并静默处理所有对象的ut8转换,甚至是从不是unicode的DB中获取的对象。所以基本上在升级之后我的代码最终重新转换为已经由AR转换为utf8的utf8字符串,结果是乱七八糟的乱码。通过完全删除after_find和after_save回调来解决问题,因为在这种情况下不再需要它们:)
答案 0 :(得分:2)
我已尝试重现您的问题,但我只能重现弃用警告,您可以通过删除
来删除它define_method(:after_find) { }
语句。
除了使用和不使用define_method语句之外,所有似乎都按预期工作。
我的代码:
class Testmodel < ActiveRecord::Base
def self.encode(*attr_names)
encoder = Encoder.new(attr_names)
before_save encoder
after_save encoder
after_find encoder
end
end
class Encoder
def initialize(attrs_to_manage) # We're passed a list of attributes that should be stored encoded in the database
@attrs_to_manage = attrs_to_manage
end
def before_save(model) # Before saving or updating, encode the attributes to their original encoding
@attrs_to_manage.each do |field|
model[field] = to_orig_encod(model[field])
end
end
def after_save(model) # After saving, encode them back to utf8
@attrs_to_manage.each do |field|
model[field] = to_utf8(model[field])
end
end
alias_method :after_find, :after_save # Do the same after finding an existing record
private
def to_orig_encod(var)
"foo"
end
def to_utf8(var)
"bar"
end
end
控制台测试:
ruby-1.9.2-p0 > Testmodel.create
=> #<Testmodel id: 3, name: nil, created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06">
ruby-1.9.2-p0 > Testmodel.last
=> #<Testmodel id: 3, name: nil, created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06">
ruby-1.9.2-p0 > Testmodel.encode('name')
=> [Testmodel(id: integer, name: string, created_at: datetime, updated_at: datetime)]
ruby-1.9.2-p0 > Testmodel.last
=> #<Testmodel id: 3, name: "bar", created_at: "2010-09-08 14:02:06", updated_at: "2010-09-08 14:02:06">
我一直在http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html咨询文档以了解您的问题: - )