Jens Krämer

What's new in acts_as_ferret Part 2 - Lazy loading

 |  ferret, rails  |  3 comments

Besides the integrated DRb server, Lazy loading of AR objects is the other big new feature in acts_as_ferret.

Until now, aaf only used the Ferret index for the retrieval of primary keys of records matching a query. These then were used to get the relevant objects out of the database via ActiveRecord. But Ferret can also store and retrieve the contents of any other field you put into the index.

This especially comes in handy for all kinds of live searches. Just store the relevant fields directly in the index and get them back from your search without a single database query. Unfortunately you’d now have to deal with two different kinds of result objects in your views - those from the index and those from your db. Not so with acts_as_ferret.

Acts_as_ferret makes the whole thing completely transparent - you can use your aaf query result as if it were a normal AR model instance. Behind the scenes aaf will only fetch the record from your databse when it needs to, that is when you ask for an attribute that could not be loaded from the index.

Say you have an Article model with the following declaration:

class Article acts_as_ferret :fields => { :title => { :store => :yes }, :excerpt => { :store => :yes }, :content => {} } end

Pay attention to the :store => :yes option for the title and excerpt fields - that’s how you tell aaf to store the title and excerpt of articles directly inside the Ferret index. Now the only thing that is left is telling find_by_contents to not prefetch all the AR records from the db:

# search articles, fetch all fields stored in the index, but don't hit the database results = Article.find_by_contents(query_string, :lazy => true) # like above, but only fetch the title fields of results results = Article.find_by_contents(query_string, :lazy => [ :title ])

In your view display the search results as usual (assuming you have a _result.rhtml partial for rendering the result list inside an ul):

<li><%= link_to h(result.title), result_path(result) %><br /><%= result.excerpt %></li>

As long as you don’t try to access any of the non-stored fields like content ore excerpt (if using the second find_by_contents example), no database query will be made to load the article.




is it possible to index only a series of objects with a special attribute into ferret vi acts_as_ferret. let's say i have some deleted objects in the database with a date set in the deleted_at atrribute that should not get indexed. i did not figure out where to set a filter that only objects with deleted_at = null get indexed. thanks in advance michael


You can override the ferret_enabled? instance method to return true only if deleted_at.nil? to achieve this.


thanks jens!

You can use Markdown here.

For the sake of spam checking any data you submit, including your IP address, will be transferred to the US based Akismet web service ( If that's not acceptable for you, you can also reach me by other means.