Most people will recognize the pattern of memoization to provide a basic caching mechanism (that’s not a misspelling, it really doesn’t have an ‘r’) :
1 2 3 4 5 6 |
class Person < ActiveRecord::Base def social_security @social_security ||= decrypt_social_security end ... end |
The big problem with this common type of memoization is that you’ve littered your method implementation with caching logic. Caching is best applied in a transparent manner – and ActiveSupport now lets you easily insert memoization into your classes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class Person < ActiveRecord::Base def social_security decrypt_social_security end # Memoize the result of the social_security method after # its first evaluation (must be placed after the target # method definition). # # Can pass in multiple symbols: # memoize :social_security, :credit_card memoize :social_security ... end @person = Person.new @person.social_security # decrypt_social_security is invoked @person.social_security # decrypt_social_security is NOT invoked |
memoize transparently aliases the method and stores the value of your method’s first evaluation in an instance variable – giving you the same functionality of the unrefined var ||= ... implementation with much less clutter.
This implementation also handles the case where you freeze your User object before ever calling the social_security method. Using conventional memoization, calls to social_security would give you a Can’t modify instance variable error instead of happily evaluating as you would want.
This implementation also will not execute the target method more than once if the original execution resulted in nil or false – which is a flaw of the conventional pattern. You can, however, force the target method to be invoked with the optional reload parameter:
1 2 3 |
# Force invocation of target method, i.e. "decrypt_social_security" # is invoked independent of there being a cached value @person.social_security(true) |
So start giving memoize some play – it’s just the right thing to do.
Update: You can now use unmemoize_all and memoize_all to undo and redo your memoized properties.
tags: ruby, rubyonrails

Hmm, I’m not sure I’m 100% a fan of this implementation. As it stands this is more code for less clarity (a separate memorize call that could get lost in the model if separated from the method definition). Perhaps I’m not seeing the big picture?
So the “memorize” call—is it misspelled?
I agree with Michael, I don’t really like this either. If you need to memoize an instance variable which isn’t the value returned form the method then would you revert to the ‘old way’ of doing things? I don’t know but checking to see whether a variable has been set or not and to initialize it if the case is latter just seems more logical to occur in code.
btw I think the ruby way of doing this is ‘very clean’
Is this the pre-cursor to a plugin or an easy extension point which let’s you memoize to something like memcache instead of the class itself? Moving this pattern out of the methods and into the meta arena certainly makes it easier to implement a system-wide memoization strategy.
Very cool. A simple, great idea. I have a few spots where this will make my code more readable and concise. I like to look at my methods and see what they are doing. Its a great idea to take any caching logic out of them since its generally there for performance reasons and not functionality.
@Michael well its less code if you consider typing out “if instance_variable_defined?( :@v ) @v else @v = ... end” compared to “memorize”. ”||=” is ok sometimes but doesnt work so well ( at all ) if there is a nil or false value returned. But I think the benefit is that your method just reads as if performance was not an issue. And when you start optimizing stuff you can cache values without mucking around in your perfectly readable methods. You just slap a memorize declaration in there and your set.
I dunno… I like it.
memorize => memoize
It was a type and I fixed in the next commit (http://github.com/rails/rails/commit/001c8beb4d0999a858a8b52ad511ee1251cc3517)
The reason reason for the abstraction was to fix freeze. If you freeze an object with memoized methods that haven’t been eager loaded, you get “Can’t modify instance variable error”. This fixes that little pain point as well.
What about stuff thar returns nil? Like, @current_user ||= User.find_by_id(session[:user]). That’ll run every time you call the current_user method if the find_by_id returns nil. Does memoize fix zhat?
Shouldn’t the line “memoize :social_security” be placed below the definition of #social_security?
I think memoizing is cool. I note however that this implementation of memoize does not work if the method the user needs to memoize takes parameters. I believe such capability is (surprisingly) easily added though—see the several lines of code of the memoize gem that does just that, for example).
Josh – thanks for your comments. I’ve updated the post with your clarifications.
Roman – you’re right about the
memoizecall needing to be below the memoized target.lethal – this
memoizedoes NOT call the original method more than one once, even if the original evaluation returnsnil. It keys its execution based on the mere existence of the cached instance variable and not its value.Glad to see this feature make it into rails. I’ve implemented it previously as a plugin called method_cache(http://github.com/humanzz/method_cache, http://humanzz.spaces.live.com/blog/cns
713.entry
). It just had one more feature: in addition to caching the result in instance variable, it also caches the result in the Rails cache store. I think that would make a nice addition to the memoize feature
I’ve never been fully understanding of the implications of using ||=. Is there a tutorial or blog post that looks at using this in depth in a rails environment?
@Chris
||= caching is a pretty simple concept. Let assume we have something like this:
class Foo def uncached_users User.find(...some crazy complex sql…) end end
So within execution cycle uncached_users method it will hit the database every single time you call it. On the other hand call to cached_users will populate instance variable that will get re-used in consequent calls instead of hitting database, thus it’s faster.
Blog killed the formatting, sorry.
Also what’s up with :memoise? It’s not even a word. Is it some type of “plane’arium” type of a joke?
@oleg: Thanks, therein lies my confusion, what defines an execution cycle.
So in your example a call to a controller/action is made, the controller does @users ||= and lets say the view just prints that out in a list.
Now lets say the user hits refresh and it goes to the same controller/action, except this time @user is already set from the last page request and thus won’t execute the right hand side of the ||=, is that right? Does that apply to just the session making the call or to all sessions?
@chris: It applies to the current request only.
@oleg: That is I thought. I find it confusing when I see people do a decleration like:
@users ||= Users.all
When its only set in that call and then the view just prints it out. Since it isn’t set anywhere else and just used in the view then why bother using ||= at all. Does it help if you do that and then access associations such as @user.company.name?
I see usage of ||= in Railscasts by RBates when it seems like he is only setting the var nad not really accessing it again except in a view and it didn’t make sense to me.
Thanks for help!
@chris: Let’s say you’re in a blog and are displaying a category of blog posts, like:
@category.some_obscure_posts
where some_obscure_posts is a method doing some crazy database hitting and processing. If I want to show:
<= @category.some_obscure_posts.size ->
At the top of the page, then
<% @category.some_obscure_posts.each do |post| -%>
further down, that’s twice I’m hitting that database with the crazy request, all in the same page load. THAT’S what this mitigates.
Please tell me this is going into rails as a plugin, or probably better, as a module that can be extended like Forwardable?
This really has no business being in rails core, IMO.
WOW, I like the fact that it doesn’t execute the original method even if it returned nil or false.
Just wondering could you do this:
class Person < ActiveRecord::Base end
I would like the code to explicitly indicate that you are assigning a value to an instance variable which is lost in the posts approach.
hmm.. or was the instance variable added purely to accommodate caching?
What about when you want to force a reload? Usually my memoized methods look something like this…
Christopher, your
reloadrequest has been answered. I’ll update the post shortly.@Ryan – very usefull post!
Whilst I find this a bi pointless, I can’t argue against the fact that a) it does have its place, b) it is a reconized technique: http://www.reference.com/browse/wiki/Memoization
But, I think it’s abstracted from the programmer in a way that means that you’ll have to go look for the call to memoize which can lead to a lot of confusion. I’d like to see this in either a block, or using some sort of altered name.
Something like: def social_security Person.memoize do decrypt_social_security end end
Or perhaps: def social_security memoize(decrypt_social_security) end
Or: def social_security memoize_decrypt_social_security end
This is way beyond my Ruby skillz, so be gentle with me. My point is, the implementation from a programmers point of view is abstract. It’s not easy to spot if somethings memoised or not. :)
I like it! Though it seems a little halting to have to define it twice…I almost wonder if ||= isn’t about as good.
Perhaps the only wrong thing in fact was the example. The memoization technique is often used to cache responses of expensive computations. Think about the factorial example in here:
http://www.reference.com/browse/wiki/Memoization
I used it a lot to cache DNS responses during slow time, or even to cache database connections easily. I wouldn’t do that like the given example, but it is a really nice and clean technique, indeed.