Memoize objects loaded with dependency injection

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?