RoR - 在obj.reload之后的after_initialize回调中的不同object_id

时间:2012-09-23 20:50:03

标签: mysql ruby-on-rails metaprogramming

我为我的项目编写了一个扩展ActiveRecord模型行为的方法,我已经删除了大部分内容,请考虑以下代码:

class ActiveRecord::Base

  def self.has_translations
    after_initialize :clear_translations_cache

    def clear_translations_cache
      binding.pry
      @_translations = {}
    end
  end
end

基本上,我希望在.reload来自数据库的实例时清除@_translations实例变量,但出于某种原因,在从数据库中获取现有对象之后,执行填充{{1}的方法然后执行@_translationsobject.reload仍然包含相同的数据。

我确信在第一次从数据库中获取对象并调用@_translations时会执行回调。我使用binding.pry来停止回调方法中的执行,但出于某种原因,.reloadself.object_id与原始对象的.reload不同,因此object_id位于@_translations之内原始对象不会被清除。

附件是控制台输出:

1.9.3p194 :008 > s = TranslatedItem.first
   76:     def clear_translations_cache
=> 77:       @_translations = {}
   78:     end

[1] pry(#<TranslatedItem>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254243993580
[3] pry(#<TranslatedItem>)> exit
1.9.3p194 :009 > s.object_id
 => 70254243993580
1.9.3p194 :010 > s.reload
   76:     def clear_translations_cache
=> 77:       @_translations = {}
   78:     end
[1] pry(#<ServiceLevel>)> self.class
=> TranslatedItem(id: integer, created_at: datetime, updated_at: datetime)
[2] pry(#<TranslatedItem>)> self.object_id
=> 70254259259120

1 个答案:

答案 0 :(得分:8)

我猜你所看到的行为与ActiveRecord reload的工作方式有关:

fresh_object = self.class.unscoped { self.class.find(self.id, options) }
@attributes.update(fresh_object.instance_variable_get('@attributes'))

你会注意到它是通过从数据库中找到它来创建一个新对象,这解释了为什么你在回调方法中看到两个不同的object_id值。在重新加载期间初始化的对象仅用于其属性,然后超出范围。

从你的问题中不清楚你是否只是好奇它为什么会这样做,或者你是否正在寻找另一种方法。

<强>更新

如果您只是在重新加载模型时正在寻找清除实例变量的方法,那么您有几个选项。

1)添加您可以显式调用的自己的重载方法:

class ActiveRecord::Base
  def reload_everything
    reload
    @_translations = {}
  end
end

object.reload_everything

2)更改重新加载的行为

module ReloadTranslations
  def reload(*args)
    super
    @_translations = {}
  end
end

ActiveRecord::Base.send(:include, ReloadTranslations)