Implementing Search in Ruby on Rails

Update: While searching like this works, it’s probably not the most efficient way. In the near future I’ll be looking into setting up Ruby/Odeum, which is a ruby binding to the QDBM Odeum inverted index library. Basically, every night a new search index would be generated, and searching would be done over this index, rather than dynamically over the database. This should greately improve performance. But until then, this is what I’m using …

I found this great post on Brandon Philips blog, which showed an example of how to search your database for relevant data, given a search string from the user. He got his inspiration from Tobias’ typo source tree, and, in turn, so did I. (Actually, mine is basically the exact same search, with some of the database column names changed. Thanks Tobias.)

song.rb
def self.search(query)
   if !query.to_s.strip.empty?
      tokens = query.split.collect {|c| "%#{c.downcase}%"}
      find_by_sql(["select s.* from songs s where #{ (["(lower(s.song_title) like ? or lower(s.song_lyrics) like ?)"] * tokens.size).join(" and ") } order by s.created_on desc", *(tokens * 2).sort])
   else
      []
   end
end

Once you’ve added the search method to your model, it’s even simpler to use.

search_controller.rb
def songs
   @query = @params["query"]
   @songs = Song.search(@query)
end

You’ll notice that I’m saving the search query into an instance variable called @query. This is so that I can output the query back to the user on the search results page, phrased like, Search results for “search query here”. If you’re going to do the same, don’t forget to sanitize the search query manually, or escape the HTML like so:

<%=h @query %>


Comments

Leave a Reply

Your email address will not be published. Required fields are marked *