Deploying ElasticSearch on Heroku with Rails 4

I recently deployed a Rails 4 app with ElasticSearch to Heroku and ran into a couple of snags along the way. I’m hoping this tutorial will be useful for others running into the same issues. Leave a comment if you have any problems or have figured out a better way! Good luck!

Step 1 – Install Elastic Search

If you’re on a Mac with Homebrew installed, simply type:

$ brew install elasticsearch

You can then confirm a proper install by navigating to http://localhost:9200:

{
  "ok" : true,
  "status" : 200,
  "name" : "Agony",
  "version" : {
    "number" : "0.90.3",
    "build_hash" : "5c38d6076448b899d758f29443329571e2522410",
    "build_timestamp" : "2013-08-06T13:18:31Z",
    "build_snapshot" : false,
    "lucene_version" : "4.4"
  },
  "tagline" : "You Know, for Search"
}

Step 2 – Create a Rails 4 app and install the elasticsearch-model and elasticsearch-rails gems


$ rails new elasticsearch_blog
$ cd elasticsearch_blog

Add these lines to your Gemfile:

gem 'elasticsearch-model' # for elasticsearch
gem 'elasticsearch-rails' # for elasticsearch

And then run:

$ bundle install

Step 3 – Add ElasticSearch to one of your Rails models

As an example, let’s create a list of posts to search through:

$ rails g scaffold Post title body:text
$ rake db:migrate

Add these lines to the Post class:

require 'elasticsearch/model'

class Post < ActiveRecord::Base
  include Elasticsearch::Model
  include Elasticsearch::Model::Callbacks
end
Post.import

Add set the root in config/routes.rb:

Rails.application.routes.draw do
  root 'posts#index'
  
  resources :posts
...

Now start up the Rails server

$ rails s

Navigate to http://localhost:3000 and create a few new posts.

Step 4 – Add a Search controller/view/route

Next generate a basic show action in controllers/searches_controller.rb:

class SearchesController < ApplicationController
def show
    if params[:q].present?
        @search = Post.search(params[:q].split.join(' AND '))
    else
      @search = []
    end
  end
end

Then add a corresponding view that includes a search form and a list of results at views/searches/show.html.erb:

<h1>Post Search</h1>

<%= form_tag(search_path, method: 'get') do %>
  <%= text_field_tag(:q, params[:q]) %>
  <%= submit_tag('Search') %>
<% end %>

<h1>Results</h1>
<ul>
  <% @search.each do |post| %>
    <li>
      <%= link_to post.title, post_path(post._id) %>
    </li>
  <% end %>
</ul>

Finally, add a route for your new search controller and view in config/routes.rb:

resource :search, only: [:show]

At this point basic search should work in your local development environment. Navigate to http://localhost:3000/search to test it.

Now let’s get it working in production on Heroku!

Step 5 – Using Postgresql in production

Add the following gems to your Gemfile:

gem 'rails_12factor', group: :production # for heroku
gem 'bonsai-elasticsearch-rails', group: :production # for Bonsai plugin on heroku
gem 'pg', group: :production # using postgresql in production

And modify this existing line to only use SQLite in Test and Development environments:

gem 'sqlite3', group: [:test, :development]

At this point if you try to run git push heroku master it should deploy without errors. However, when you try to navigate to your app on Heroku you’ll likely see this warning:

Application Error

An error occurred in the application and your page could not be served. Please try again in a few moments.

If you are the application owner, check your logs for details.

And if you check your Heroku logs through the command line:

$ heroku logs

The last line might show something like:

2014-09-25T14:49:23.353648+00:00 heroku[router]: at=error code=H10 desc="App crashed" method=GET status=503

Not to worry! We’re getting close.

Step 6 – Install the Bonsai Elasticsearch add-on

If you already have your Heroku account’s billing information in order you can simple run:

heroku addons:add bonsai

Which will add the Bonsai Elasticsearch add-on to your production app.

Now create these two files in your Rails app:

lib/tasks/elasticsearch.rake

require 'elasticsearch/rails/tasks/import'

config/initializers/bonsai.rb

require 'elasticsearch/model'

if ENV['BONSAI_URL']
  Elasticsearch::Model.client = Elasticsearch::Client.new({url: ENV['BONSAI_URL'], logs: true})
end

Commit these changes and push to Heroku. Everything should load up properly (except for your app).

Step 7 – Create an index for ElasticSearch on Heroku

On the command line, confirm that installing the Bonsai add-on in Step 6 automatically created the BONSAI_URL environmental variable by running:

$ heroku config | grep BONSAI
BONSAI_URL => http://your:bonsai@url-here.us-east-1.bonsai.io/

You’re now ready to create a new search index for your app! Copy your BONSAI_URL and then run:

$ curl -XPUT https://your:bonsai@url-here.us-east-1.bonsai.io/posts
{"ok":true,"acknowledged":true}

And:

$ heroku run bundle exec rake environment elasticsearch:import:model CLASS='Post' FORCE=true
Starting up a new ElasticSearch client with https://e0zqh3p8:hc1i40s129fefaug@smoke-5079344.us-east-1.bonsai.io
[IMPORT] Done

If you run into any problems or error messages at this point, make sure that you’ve run a migration for your Heroku app:

$ heroku run rake db:migrate

And then run the elasticsearch:import command again.

Finally restart your app:

$ heroku restart -a

And that’s it! Elasticsearch should now being running on your Rails 4 app deployed on Heroku. Test it out by first adding a few posts by navigating to http://.herokuapp.com and then visit http://.herokuapp.com/search to see Elasticsearch in action.

3 thoughts on “Deploying ElasticSearch on Heroku with Rails 4”

  1. I am SO glad I came across this! I had been muddling along trying to get elastic search working, and all the while missing those last 5 steps from your walkthrough. Not sure if I just didn’t notice them elsewhere, or they didn’t show up when I was searching, but I am certainly glad I happened across this. Thank you very much!

  2. This writeup saved my life – you covered the last missing gap in getting elasticsearch running in prod on Heroku. Thanks for sharing this!

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>