升级到rails3后,after_find回调中断

时间:2010-09-07 18:09:14

标签: ruby-on-rails ruby ruby-on-rails-3

素不相识!

在一个在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回调来解决问题,因为在这种情况下不再需要它们:)

1 个答案:

答案 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咨询文档以了解您的问题: - )