代码之家  ›  专栏  ›  技术社区  ›  svilenv

升级到rails3后发现回调中断

  •  1
  • svilenv  · 技术社区  · 14 年前

    格雷廷斯!

    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
    

    此方法引用编码器类。给你:

    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之前,所有回调(保存前、保存后、查找后)都正常工作。升级后 保存前 保存后 没有,我在日志中收到以下弃用警告:

    DEPRECATION WARNING: Base#after_find has been deprecated, please use Base.after_find :method instead
    

    我不确定如何更改代码以重新启用after\u find回调的功能。我尝试了一些简单的替代方法,但没有成功,关于这个回调的railsapi文档非常有限,而且没有实现的例子。

    感谢您的帮助,谢谢!

    编辑:

    以下是解决方案:

    好吧,看来问题比最初看起来更微妙。在额外的测试之后,我发现事实上,正如Jeppe所指出的那样,After\u find回调是有效的,不管是否有弃用警告,“to\u utf8”方法实际上是成功地被调用并在模型属性上执行的。结果与预期不符的原因是“toutf8”方法本身。它使用ruby模块Iconv将字符串从非utf8编码(例如cp1251)转换为utf。这是为使用活动记录从非utf编码的远程遗留数据库中获取的模型属性完成的。然而,事实证明,与以前版本的rails不同,Rails3中的AR 自动 并且静默地处理所有对象到ut8的转换,甚至那些从不是unicode的DB获取的对象。所以本质上在升级之后,我的代码最终重新转换成utf8字符串,这些字符串已经被AR转换成utf8,结果是乱七八糟的字符。通过完全删除after\u find和after\u save回调可以解决此问题,因为在本例中不再需要它们:)

    1 回复  |  直到 14 年前
        1
  •  2
  •   Jeppe Liisberg    14 年前

    我试图重现您的问题,但我只能重现弃用警告,您可以通过删除

    define_method(:after_find) { }
    

    声明。

    我的代码:

    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 要理解你的问题:-)