How to Implement Elasticsearch in Rails

Elasticsearch is an open-source, RESTful search engine built in Java, but it's possible to use it in Rails as well. Here, I'll walk through getting started with downloading and using it in a simple Rails application, utilizing the Searchkick gem. 

Install

If you don't have Java installed, get started by typing in the console: 

$ brew install Caskroom/cask/java

This process involves a large download, so if you're not on a fast connection it may take a while. Then you can install Elasticsearch with: 

$ brew install elasticsearch

This should also start a download, which finishes with a set of instructions. If you've never used Elasticsearch before, you'll have to load and launch it now: 

$ ln -sfv /usr/local/opt/elasticsearch/*.plist ~/Library/LaunchAgents
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.elasticsearch.plist

At this point, you can navigate to localhost:9200 and should be able to see a JSON object indicating that you've got Elasticsearch stable and installed on the machine. If you don't see that, pause here and troubleshoot. The Elastic Ruby API Documentation is a helpful resource.

Searchkick

I'm also going to use the Searchkick gem to get our search functionality going, so you can install that by adding to the Gemfile: 

gem 'searchkick', '0.8.3'

And run bundle install. Next, we'll need to add the word 'searchkick' to the model we'll be searching. For this example, I've got a yelp-like application with a place model 

class Place < ActiveRecord::Base
  searchkick 
end

If you already have any data within the model you're implementing it for, then you can reindex that information with a rake command. 

rake searchkick:reindex CLASS=Place

We'll also need search functionality in the routes.rb file for our places model. 

Rails Integration

resources :places do 
  collection do 
    get 'search' 
  end
end 

Next, we'll need to add in user functionality to search in the browser. You can do this a variety of ways, but in this application I've already got a header partial that will allow users to search on every page. 

<!-- app/views/layouts/_header.html.erb -->
<%= form_tag search_places_path, method: :get, class: "navbar-form navbar-right", role: "search" do %>
  <p>
    <%= text_field_tag :search, params[:search], class: "form-control" %>
    <%= submit_tag "Search", name: nil, class: "btn btn-default" %>
  </p>
<% end %>

In the controller, we'll need to add in functionality that tells the application how to search. There are numerous ways to implement this, but I'll just use a basic search method in places_controller.rb

def search
  if params[:search].present?
    @places = Place.search(params[:search])
  else 
    @places = Places.all
end

Almost finished! At this point, we just need to add in a view file and ensure we have some data to search through. I created a new file similar to places#index: 

<!-- app/views/places/search.html.erb -->
<% @places.each do |p| %>
  <%= link_to (image_tag p.image.url(:medium), class: 'image'), p %>
  <%= p.name %> 
<% end %>

Now, using the header at the file I can search for various elements of Places in the database, and I should be able to see their image representation and name on the search page. In fact, you can even see the search parameters that were sent through in the URL. For example, if you search for "cafe", it shows: http://localhost:3000/places/search?utf8=%E2%9C%93&search=cafe. 

If you have any questions, just let me know. Happy searching!