升级到 rails3 后 after_find 回调中断 [英] after_find callback broken after upgrade to rails3

查看:46
本文介绍了升级到 rails3 后 after_find 回调中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问候!

在 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_saveafter_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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆