A Fresh Cup is Mike Gunderloy's software development weblog, covering Ruby on Rails and whatever else I find interesting in the universe of software. I'm a full-time Rails developer and contributor, available for long- or short-term consulting, with solid experience in working as part of a distributed team. If you'd like to hire me, drop me a line. I'm also the author of Rails Rescue Handbook and Rails Freelancing Handbook.

Navigation
« Double Shot #391 | Main | Double Shot #390 »
Thursday
Feb122009

A Note on Memoization in Rails

If you've been following along at home, you know that memoization was added to Rails 2.2 as a shortcut for a common idiom:

[sourcecode language='ruby']
def site_term_ids
@site_term_ids || = cached_terms.split.map
{ |term| Term.find_by_query(term).id }
end
[/sourcecode]

Memoization makes it possible to perform an expensive operation once, and then cache the results for future calls to the same property. What you may have missed, though, is that this isn't baked into Active Record; it's a separate part of Active Support. So if you're getting mystery errors about memoization not working, be sure you're including the right extension:

[sourcecode language='ruby']
class Site < ActiveRecord::Base
extend ActiveSupport::Memoizable

def site_term_ids
cached_terms.split.map
{ |term| Term.find_by_query(term).id }
end
memoize :site_term_ids

end
[/sourcecode]

Reader Comments (5)

Just a note, memoize doesn't play with with Model#destroy as both mess with Object#freeze

February 13, 2009 | Unregistered CommenterPratik

Hmm... this replaces a simple Ruby idiom with a module and a method of unknown complexity. I don't find it very compelling, I have to say...

February 14, 2009 | Unregistered CommenterAshley Moran

I agree with Ashley, but I'd go as far as to say it's ridiculous. It's obfuscation, and to what end? I've been looking forward to Rails 3, but if this kind of code is still the order of the day then maybe I should start to worry.

February 27, 2009 | Unregistered CommenterGraham Ashton

@ Ashley and Graham
memoize doesn't just replace a Ruby idiom, it improves it. With caching, your expensive operation will run every time if the result is nil or false. Memoize will remember the value no matter what it is. Also caching will fail if you operation is based on any arguments, but memoize will remember the result for each set of arguments.

April 11, 2009 | Unregistered CommenterWade West

What I love about the new memoize functionality is that it is so well documented.

What I a supposed to do, walk through the test cases and try to divine the capabilities from them?

If it doesn't play nice with destroy, then there are substantial problems.

As for specifics, the example cited are simplified. If your function takes arguments, the idiom looks like:

def initialize
...
@cached_func_vals = {}
...
end

def func(*args)
return @cached_func_vals[args] if @cached_func_vals.has_key? args
... do computations ...
value = last computation
@cached_func_vals[args] = value
end

May 8, 2009 | Unregistered Commenterstudent

PostPost a New Comment

Enter your information below to add a new comment.
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>