【问题标题】:How to fully reload an ActiveRecord to reset it's memoized values?如何完全重新加载 ActiveRecord 以重置它的记忆值?
【发布时间】:2015-04-01 14:06:57
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: ruby-on-rails ruby activerecord rspec


    【解决方案1】:

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

    您不能以任何简单的“Rails”方式“重新加载”对象的记忆值,因为记忆属性不是 Rails 或 ActiveRecord 的功能。两者都不知道你是如何记忆方法的。

    【讨论】:

    • 2016年还是这样?
    • 2017年还是这样吗?我们能以某种方式记住直到第一次重新加载吗?
    【解决方案2】:

    您可以通过重新定义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

    【讨论】:

      【解决方案3】:

      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 是不够的,因为它已经是被定义并尽早返回。

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

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

      【讨论】:

        猜你喜欢
        • 2016-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-02-18
        • 1970-01-01
        相关资源
        最近更新 更多