我为我的项目编写了一个扩展 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 实例变量被清除,但出于某种原因,在从数据库中获取现有对象后,执行填充 @_translations
的方法,然后执行 object.reload
, @_translations
仍然包含相同的数据。我确信在第一次从数据库中获取对象和调用
.reload
时会执行回调。我使用 binding.pry 来停止回调方法内的执行,但由于某种原因,self.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
最佳答案
我猜你看到的行为与 ActiveRecord reload 的工作方式有关:
fresh_object = self.class.unscoped { self.class.find(self.id, options) }
@attributes.update(fresh_object.instance_variable_get('@attributes'))
您会注意到它通过从数据库中查找来创建一个新对象,这解释了为什么您在回调方法中看到两个不同的 object_id 值。在重新加载期间初始化的对象仅用于其属性,然后超出范围。
从您的问题中不清楚您是否只是好奇它为什么会这样,或者您是否正在寻找替代方法来做到这一点。
更新:
如果您只是在寻找一种在重新加载模型时清除实例变量的方法,那么您有几个选择。
1) 添加您自己可以显式调用的 reload 方法:
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)
关于mysql - RoR - obj.reload 后 after_initialize 回调中的不同 object_id,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12556135/