如何完全重新加载 ActiveRecord 以重置其记忆值?

How to fully reload an ActiveRecord to reset it's memoized values?

在 RSpec 测试中,我创建了一个包含多个记忆值的记录。

foo.reload 对象的属性按预期工作,但记忆的属性仍然存在。

到目前为止,它通过完全重新创建对象来工作:foo = Foo.find(123)但在我的例子中,查找记录的逻辑实际上更复杂。

什么是完全重新加载记录并擦除所有记忆值的好方法?

好的方法是您已有的方法:完全重新创建对象。

您不能 "reload" 对象的记忆值以任何简单的 "Rails" 方式,因为记忆属性不是 Rails 或 ActiveRecord 的功能。他们都不知道你是如何记忆方法的。

您可以通过重新定义 reload 来做到这一点。例如,如果您使用 ||= 进行记忆,您可以这样做:

class Foo < ActiveRecord::Base
  def bar
    @bar ||= rand
  end

  def reload
    @bar = nil
    super
  end
end

有关重置所有实例变量的方法,请参阅 Is there a clean API for resetting instance variables on 'reload' in ActiveRecord?

如果您使用 memoist gem,您可以在那里调用 flush_cache

Michael 的回答是正确的,但请注意,如果您使用 the more sophisticated pattern for also memoization nil and false values,那将不会重置记忆。

例如,使用文章中的相同示例进行记忆 nilfalse 值:

def main_address
  return @main_address if defined? @main_address
  @main_address = begin
    main_address = get_home_address_from_api
    main_address ||= get_work_address_from_api
    main_address ||= another_api_call.first
  end
end

这个模式非常有效,因为它还记忆了 nilfalse,但是当然,要重置它,仅仅将 @main_address 设置为 nil,因为它已经被定义并且 return 早。

在这些情况下,您应该像这样重置它:

def reset_main_address_memoization
  self.send(:remove_instance_variable, :@main_address) if instance_variable_defined?(:@main_address)
end