Hi,
I’m throwing a topic here to see if anyone has been through a similar situation and see how you sorted it out.
TL;DR Would you use @attributes_cache
for memoizing a dependent object? Would you have a better suggestion?
Imagine you have an Order
model, which inherits from ActiveRecord::Base
. Sometimes you need to run some complex/slow calculation which is performed by another class, you run those calculations with this:
order = Order.find 1
order_metrics = OrderMetrics.new order
Then I can access the metrics by just calling the methods from order_metrics
, for example: order_metrics.average_time_per_week
.
As the OrderMetrics
always requires an order, I find it convenient to provide it as a method of the order. So, in the Order class I implemented the following method:
def metrics
OrderMetrics.new self
end
So I can call it like this:
Order.find(1).metrics.average_time_per_week
But just so it’ll run faster on successive calls, I modified the method implementation to this:
def metrics
@metrics ||= OrderMetrics.new self
end
But because the metrics depend on the values of the order, I want the metrics object to be discarded if any changes happen in the order. For example:
order = Order.find 1
order.metrics.average_time_per_week # => whatever value
order.update_attribute(:created_at, 1.day.ago)
order.metrics.average_time_per_week # => this value is no longer valid
order.instance_value_set :@metrics, nil
order.metrics.average_time_per_week # => this is the correct new value
So this has been my final implementation:
def metrics
@attributes_cache[:metrics] ||= OrderMetrics.new self
end
I don’t like this solution mainly because I think it’s using Rails’ private API. However I can’t think of a better way to memoize this dependent object and discard it on any update.
Have you ever had a similar problem to this?