Full Text Search With Ruby on Rails
2011-07-30 07:16:04 | 2 Comments
I'm working on something and I needed a search functionality so I did check out my options. I did not prefer MySQL's full text search functionality as I don't want MySQL to deal with it where there are tools created only for that. I did take a look at [Sphinx](http://sphinxsearch.com/), [Solr](http://lucene.apache.org/solr/) and [ElasticSearch](http://www.elasticsearch.org/). Among three of them I did prefer Solr. Luckily, kudos to [Mat Brown](http://outofti.me/) he had created a Solr gem for Ruby called [Sunspot](https://github.com/outoftime/sunspot) and a Ruby on Rails plugin on top of it called Sunspot Rails. In order to make it compact, I will explain all this with creating a sample Rails application.
Creating the Rails Application
----------
Let's create a new Rails application and generate a model and its scaffold.
rails new rails_fulltext_search -d mysql
cd rails_fulltext_search
sudo bundle install
rails g scaffold Company name:string city:string state:string country:string
Installing Sunspot Rails
----------
Like installing any other Rails plugin or Ruby gem with Rails, we simply add `gem 'sunspot_rails'` to your Gemfile and run `bundle install`. Start Solr instance with `rake sunspot:solr:start`
echo "gem 'sunspot_rails'" >> Gemfile
sudo bundle install
rake sunspot:solr:start
A note: If you get an error complaining like "libxml2 not found" from nokogiri, you can do `sudo apt-get install libxml2-dev` and install it on Ubuntu.
Indexing the Model
----------
Now that we have a Company model that has 'name, city, state, country' fields. How do we make Solr index it? The following is the answer.
class Company < ActiveRecord::Base
searchable do
text :name
string :city
string :state
string :country
end
end
What does this `text` and `string` do here? When we tell Sunspot that `name` is a `text` field, it automatically tokenizes it, applies default filters and downcases it and we use the `keywords()` method to find indexed `text` data however when we use `string`, it does not do anything and the data marked as string can only be searched as is by the `with()` method.
By default, whenever we create new Company objects, they will be indexed automatically. What about our current data? You can index them by running `rake sunspot:solr:reindex` command.
How to Implement Search Functionality
----------
Let's add a search action in our companies_controller and create the corresponding view in `/app/views/companies/` called `search.html.erb`.
# goes in app/controllers/companies_controller.rb
def search
if params[:commit]
@companies = Company.search do
if params[:name]; keywords(params[:name]); end
[:city, :state, :country].each do |field|
if params[field] != ""; with(field, params[field]); end
end
end.results
end
end
We implement both searching and displaying results in one action. It's not a must or must not do. Do whatever pleases you. The following is our corresponding view.
# app/views/companies/search.html.erb
<% if !params[:commit] %>
Search companies
<%= form_tag('/companies/search', :method => 'get') do %>
<%= label_tag :name %>
<%= text_field_tag :name %>
<%= text_field_tag :name %>
<%= label_tag :city %>
<%= text_field_tag :city %>
<%= text_field_tag :city %>
<%= label_tag :state %>
<%= text_field_tag :state %>
<%= text_field_tag :state %>
<%= label_tag :country %>
<%= text_field_tag :country %>
<%= text_field_tag :country %>
<%= submit_tag 'Search' %>
<% end %>
<% else %>
<% if @companies %>
Search results
-
<% @companies.each do |company| %>
- <%= link_to company.name, company_path(company) %> <% end %>
Did you enjoy this post? You should follow me on twitter here.


Comments
Leave a Response