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.rbdef 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.rbdef 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 %>
Leave a Reply