When you do something like this in your code:
def var_value
@var ||= some_expensive_calculation
end
Be aware that it will run some_expensive_calculation every time you call var_value if some_expensive_calculation returns nil.
This illustrates the problem:
def some_expensive_calculation
puts "i am off shopping bits!"
@some_expensive_calculations_result
end
When you set @some_expensive_calculations_result to nil, ||= runs some_expensive_calculation every time.
> var_value
i am off shopping bits!
=> nil
> var_value
i am off shopping bits!
=> nil
> var_value
i am off shopping bits!
=> nil
This only changes, when @some_expensive_calculations_result is something other than nil:
> @some_expensive_calculations_result = 42
=> 42
> var_value
i am off shopping bits!
=> 42
> var_value
=> 42
> var_value
=> 42
So when you are in performance trouble if you do something like this:
def show
@resource ||= User.find(resource_params(:id))
end
It will only cache only if a valid @resource is found. If the result is nil, the database is asked again and again.
Why?
'||=' is a shorthand vor "nil or undefined", so if you want to cache something that can return nil, you can not use it. You will have to check for 'defined?' only, ignoring 'nil?'
something like this would be correct:
def cache_or_resolve(instance_variable_name, resolver)
if !instance_variable_defined? "@#{instance_variable_name}"
instance_variable_set("@#{instance_variable_name}", send(resolver))
end
instance_variable_get("@#{instance_variable_name}")
end
def var_value
cache_or_resolve :var, :some_expensive_calculation
end
This is what "memoize" in earlier rails versions did. There is a gem Show archive.org snapshot that reintroduces this behavior, but this is the essential implementation.
Remember
In the above example, some_expensive_calculation is never called again. This might be what you want, but if you are looking for something in the database that might return a valid result later on, you need to invalidate the cache manually:
def var_value_refreshed
remove_instance_variable "@var"
var_value
end
For the "propper" solution, see the gem mentioned. This only outlines the gun, the foot and the trigger.