升级到 rails3 后 after_find 回调中断 [英] after_find callback broken after upgrade to rails3
问题描述
问候!
在 Rails 2.3.8 中完美运行的应用程序中,我有以下类方法:
In an app that was working flawlessly in Rails 2.3.8 i have the following class method:
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 类.这是:
This method references the Encoder class. Here is it:
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 不起作用,我在日志中收到以下弃用警告:
Before the upgrade to rails3 all the callbacks (before_save, after_save, after_find) worked fine. After the upgrade before_save and after_save still work, but after_find does not and I get the following deprecation warning in my log:
DEPRECATION WARNING: Base#after_find has been deprecated, please use Base.after_find :method instead
我不确定如何更改我的代码以重新启用 after_find 回调的功能.我尝试了一些简单的更改,但没有成功,关于此回调的 rails API 文档非常有限,而且没有实现示例.
I'm uncertain how to change my code in order to re-enable the functionality of the after_find callback. I tried a few simple alternations with no success and the rails API documentation on this callback is very limited and without examples of implementation.
感谢任何帮助,提前致谢!
Any help appreciated, thanks in advance!
解决办法如下:
好的,问题似乎比最初出现的更微妙.经过额外的测试,我发现事实上,正如 Jeppe 所指出的,无论是否有弃用警告,after_find 回调都在工作,to_utf8"方法实际上是在模型属性上成功调用和执行的.结果与预期不符的原因是to_utf8"方法本身.它的作用是使用 ruby 模块 Iconv 将字符串从非 utf8 编码(如 cp1251)转换为 utf.这是为使用 Active Record 从非 utf 编码的远程遗留数据库中获取的模型属性完成的.然而,事实证明,与以前版本的 rails 不同,rails 3 中的 AR 自动 并默默地处理所有对象到 ut8 的转换,即使是那些从不是 unicode 的 DB 中获取的对象.所以基本上在升级之后,我的代码最终重新转换为 utf8 字符串,这些字符串已经被 AR 转换为 utf8,结果是一堆乱码.通过完全删除 after_find 和 after_save 回调解决了问题,因为在这种情况下不再需要它们:)
Okay, so it seems that the problem was more subtle than it initially appeared. After additional testing I found out that in fact, as Jeppe pointed out, the after_find callback is working regardless of the deprecation warning, the "to_utf8" method was in fact suceesfully called and executed on the model attributes. The reason the result didn't match the expectations, was the "to_utf8" method itself. What it does is use the ruby module Iconv to convert strings from non-utf8 encoding like cp1251 for example to utf. This was done for the attributes of a model fetched with Active Record from a remote legacy database with non-utf encoding. However, as it turned out, unlike previous versions of rails, AR in rails 3 automagically and silently handles the conversion to ut8 of all objects, even those fetched from DB's that are not unicode. So essentially after the upgrade my code ended up re-converting to utf8 strings that were already converted to utf8 by AR and the result was a mess of gibberish characters. The problem was resolved by completely removing the after_find and after_save callbacks, since they are no longer needed in this case :)
推荐答案
我已经尝试重现你的问题,但我只能重现弃用警告,你可以通过删除你的来摆脱
I've tried to reproduce your problem, but I can only reproduce the deprecation warning, which you can get rid of by deleting your
define_method(:after_find) { }
声明.
除此之外,无论是否使用define_method 语句,一切似乎都按预期工作.
All seems to work as expected besides that, both with and without the define_method statement.
我的代码:
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 以了解您的问题 :-)
I've been consulting the documentation at http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html to understand your question :-)
这篇关于升级到 rails3 后 after_find 回调中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!