Posts [ 18 ]

Topic: HOWTO: Adding search to your rails application

Sticky:: Please read the post below. I think you will find the next method even simpler.

This is a short guide on adding search to your Rails models. For this tutorial, I'm using a model called Product and product has the following attributes: name, description, price. If you're new to rails, what this means is that you have a database table called products, and this table has the columns name, description and price (including id of course).

Now, the first thing to do is to install the ferret gem. Without this, this tutorial is moot. Open a command prompt and type:

gem install ferret

Next, you will need to download the simple_search plugin for rails. The svn repositry is located at:

Now there is a bit of explaining to do here. In addition to all the other columns Product has, you should also add another one called idx which has the type "TEXT" in your SQL database. This means that the columns for product should be id, name, description, price and idx (which is a TEXT column). idx contains the searchable terms for your product. You will notice the line at the top which reads "indexes_columns :title, :description, :into => 'idx' ". Well simple_search simply takes the value of these columns and creates a searchable index which it puts into the idx column. I could well have said "indexes_columns :title, :description, :price :into => 'idx' " which will also include the price as part of our index.

I've added some filters to the product model. Before a product is saved or updated, the idx value is first determined using the 'make_index' method. This saves you the trouble of doing this in your controller each time you save or update your product.

And that is pretty much it. You can fire up script/console with "ruby script/console" for your application.Create a new product with

Copy the code listing at the very end of the website above and save it as a file called search.rb. Place the search.rb file in the lib folder of your rails application. Now lets say you have a model called Product, do the following:

searches_on defines what columns I want to be made searchable. I can also say

searches_on :title, :description, :list_price

to search only these columns.Now to search my product, all I have to do is say:

Product.search("ninja turtle")

If I need to search for many different queries I should say Product.search("ninja turtle or transformer") but this didn't really work for me because I don't want my users to type strange commands. So this is the search method I'm using:

Product.search(params[:query].gsub(' or ',' ').split().join(' or ')

This works for me and should work for you too. This is much simpler than the previous method using simple search.

Re: HOWTO: Adding search to your rails application

I should note that the above paginating does not work for searches, because when you go to page two the search query defaults to nothing and you lose all your search results. Haven't figured out a clean solution to that just yet.

Re: HOWTO: Adding search to your rails application

Great tutorial! How to search by category ? I mean if I'm developing my school library website, how I want to let the students search by by Category, Year, Author ? Like this forum search options. Thanks!

Re: HOWTO: Adding search to your rails application

In the tutorial, the model provides two methods, "search_name" and "search_all."

For what you're trying to do, I would just provide one search method -- "search_author". I suspect search is overkill for the other two conditions, "category" and "year".

There's probably no need to "search" categories; you already know what they are. It's more of a filter, where you might pass an argument like ":conditions=>["category = 'fiction']. It's the same with year; you really don't need to 'search' it -- you're just going to filter for "1987" or ">1994 AND <2004". You're not going to search in the "year" field for terms like "Einstein" AND "math", so it isn't a search, per se.

Anyway, once your model returns its array of results, you could paginate and semantically label the pages with author data, so that the results are neatly broken into pages labeled "Aaron to Byron", "Camille to Dante", etc.

If it's a multi-year search, you could label them with "Able, 1883 to Anderson, 1994" and "Astarte, 1776 to Ballinger, 1923" or the other way around, like: "1810, Pursley to 1850, Bedinger" and "1851, Sydney to 1876, Lincoln" depending on your ordering of the results.