Navigation bar About Projects Clients Contact Blog

Posts Tagged ‘searchlogic’

Using Searchlogic to Simplify Rails Search

posted November 23rd, 2009 by ClaraClara

We’ve been working on a new social networking site, and I’ve been integrating Searchlogic for the first time to help make searching for users and posts easier. I saw Searchlogic’s creator give a presentation at a Boston Ruby meetup, and I was pretty psyched to learn about the existence of this simple way to keep the code for this common task clean and DRY.

First, we needed a way for visitors to search for user profiles simply by the fields that are in the database. Easy! Searchlogic has this built-in.

In the view:

<% form_for @search, :html => {:method => 'post'} do |f| %>
Username: <%= f.text_field :login_like %>
First Name: <%= f.text_field :first_name_like %>
Last Name: <%= f.text_field :last_name_like %>
Bio: <%= f.text_field :bio_like %>
Career: <%= f.text_field :career_like %>
Education: <%= f.text_field :education_like %>
<%= submit_tag 'search' %>
<% end %>

And in the controller, where the real savings happens:

if request.post?
 @search = User.search(params[:search])
 @users = @search.all
else
 @search = User.search
end

Searching on all the user’s fields, with just a couple lines of code!

In searching posts, we needed some slightly more complicated searches; we’re using acts_as_taggable_on_steroids and wanted users to be able to search for posts with particular tags, and we also wanted a way to use the post’s belongs_to association to allow users to search for posts entered by a particular user. Since Searchlogic allows us to define our own named scopes, we just need to add a couple of lines to the model to be ready to use the same tricks we used searching on database fields:

named_scope :has_tags, lambda {  |tags|
    Post.find_options_for_find_tagged_with(tags, :match_all => true)
  }
named_scope :poster_login_like, lambda { |c| { :joins => ["LEFT OUTER JOIN users ON (users.id = posts.poster_id)"], :conditions => ['users.login LIKE ?', c]
  }}

We also wanted searching for post content to include a search of the post body. So the view looks like this:

<% form_for @search, :html => {:method => 'post'} do |f| %>
Containing:  <%= f.text_field :content_like %></p>
<p>Tagged with: <%= f.text_field :has_tags %></p>
<p>By Username: <%= f.text_field :poster_login_like %></p>
<%= submit_tag 'search' %>
<% end %>

And the controller has the same super-simple:

    if request.post?
      @search = Post.search(params[:search])
      @posts = @search.all
    else
      @search = Post.search
    end

This is one of the things I love about working with Rails — thanks to all the great gems and plugins out there, we can do complex stuff with just a few lines of code rather than re-inventing the wheel.