– we create awesome web applications

On one of our projects we needed to do some caching for an action with an expensive db query. Fragment caching took care of the rendering but we needed a way to skip the db if we have a cache hit. And checking for an existence of the fragment file in the controller just didn’t seem right.

Lazy evaluation to the rescue.

controller

@items = Item.lazy.paginate

view

<% cache ("fragment...") do %>
   <%= render :collection => @items %>
<% end %>

@items is a placeholder for the result of calling paginate which will not be actually executed until @items is used in any way (calling any method on it, like each, or to_s). And if the fragment is cached then @items is not accessed and so no db query is made.

We re-implemented the lazy evaluation recently for our new project with a much cleaner syntax and simpler implementation. We packaged it as lazyeval gem.

Sources can be found at github. The interesting part is in lazyeval.rb which is just 28 lines long. Check it out …

The basic idea is to return a placeholder object that ‘remembers’ what needs to be done once it is used.

2 options:

  1. foo.lazy.bar(params) - this will return a placeholder that will call method bar on the object foo with params once used.
  2. foo.lazy {|o| o.bar } - this will return a placeholder that will call the block passing the object foo as a parameter.