In an RSpec test, I create a record that has several memoizied values.
foo.reload
works as expected for the object's attributes, but memoized ones are still present.
So far, it works by completely recreating the object: foo = Foo.find(123)
but in my case, the logic for finding the record is actually more complex.
What's a good, DRY way to fully reload the record and erase all memoized values?
You can do that by redefining reload
. For example if you memoized with ||=
you can do that:
class Foo < ActiveRecord::Base
def bar
@bar ||= rand
end
def reload
@bar = nil
super
end
end
For ways to reset all instance variables see Is there a clean API for resetting instance variables on 'reload' in ActiveRecord?
If you use the memoist gem you can call flush_cache
there.
The good way is the one you already have: Completely recreating the object.
You cannot "reload" the object's memoized values in any easy "Rails" way, as memoizing attributes isn't a function of Rails or ActiveRecord. Neither knows anything about how you're memoizing methods.
Michael's answer is sound, but be aware that if you use the more sophisticated pattern for also memoization nil
and false
values, that will NOT reset the memoization.
For instance, using the same example from the article for memoization nil
and false
values:
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
This pattern works great because it also memoizes nil
and false
, but of course, to reset it, it wouldn't be enough to simply set the @main_address
to nil
, because it would be already be defined and return early.
In these cases, you should reset it like this:
def reset_main_address_memoization
self.send(:remove_instance_variable, :@main_address) if instance_variable_defined?(:@main_address)
end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With