如何完全重新加载 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,那将不会重置记忆。
例如,使用文章中的相同示例进行记忆 nil
和 false
值:
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
这个模式非常有效,因为它还记忆了 nil
和 false
,但是当然,要重置它,仅仅将 @main_address
设置为 nil
,因为它已经被定义并且 return 早。
在这些情况下,您应该像这样重置它:
def reset_main_address_memoization
self.send(:remove_instance_variable, :@main_address) if instance_variable_defined?(:@main_address)
end
在 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,那将不会重置记忆。
例如,使用文章中的相同示例进行记忆 nil
和 false
值:
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
这个模式非常有效,因为它还记忆了 nil
和 false
,但是当然,要重置它,仅仅将 @main_address
设置为 nil
,因为它已经被定义并且 return 早。
在这些情况下,您应该像这样重置它:
def reset_main_address_memoization
self.send(:remove_instance_variable, :@main_address) if instance_variable_defined?(:@main_address)
end