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

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 =[:q].split.join(' AND '))
      @search = []

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 %>

  <% @search.each do |post| %>
      <%= link_to post.title, post_path(post._id) %>
  <% end %>

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:


require 'elasticsearch/rails/tasks/import'


require 'elasticsearch/model'

  Elasticsearch::Model.client ={url: ENV['BONSAI_URL'], logs: true})

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

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

$ curl -XPUT


$ heroku run bundle exec rake environment elasticsearch:import:model CLASS='Post' FORCE=true
Starting up a new ElasticSearch client with

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 and then visit to see Elasticsearch in action.

CSS namespacing for Rails controllers and actions

Do you ever find yourself fighting with CSS conflicts in the asset pipeline? Heres’s a handy namespacing trick mentioned by Brian Morearty in his Rails 4.1 Performance Fundamentals course. You can easily apply style rules to all pages of one controller, or specifically target a single action in a controller, by adding the current controller and action as class names to the body tag in your application.html.erb view file:

<body class="<%= request.params[:controller] %> <%= request.params[:action] %>">

Now you can use these generated classes in your style sheets. Let’s say your application is a blog with posts. You can now organize your controller-specific styles like this:

.posts {
  // styles that would affect all pages of the posts controller
} {
  // styles that would only affect the show action view of the posts controller

You can also add a .content class around the yield in application.html.erb to make sure your CSS styles only affect the main part of the page and not the application’s layout:

<div class="content">
  <%= yield %>
</div> .content {
  // styles that would only affect the posts show page content and not the layout 

Active Record enums in Ruby on Rails 4.1

I was recently working on a Rails app that required role-based authorization for its users. Basically, the application would need the ability to check to see if the user had the proper credentials to access certain features of the site.

I’ve typically handled this in the past by either adding an admin boolean column in the Users table so I could simply call @user.admin? to check to see if the user is an admin or not, or for situations which require multiple levels of authorization (or the ability to give a user more than one set of privileges at a time), adding a many-to-many association between the User model and another model called Role. This many-to-many association also requires a join table called role_user. The latter approach is obviously more complex and requires the creation of several helper methods to become convenient to use.

Since I was using Rails 4.1 for this project and because each user only needed to be granted one user role at a time, I figured I would give the new ActiveRecord::Enum feature a try. Rails now provides a really simple way to quickly add attributes and a bunch of associated helper methods to an Active Record class.

For example, when I added this one line to my User model:

class User < ActiveRecord::Base
  enum role: [:reader, :contributor, :admin]

I got all of these convenience methods for free:

user.contributor? # => true
user.role  # => "contributor"

user.contributor? # => false
user.admin? # => true
user.role # => "admin"

User.admin # => relation for all admin users

User.roles # => { "reader" => 0, "contributor" => 1, "admin" => 2 }

The only additional thing you need to get these Active Record enums working is a migration to add the attribute to the model, in this case adding role to User. Notice that this column is an integer value, which is mapped to the index of each enum value:

$ rails g migration AddRoleToUsers role:integer

which automatically generates:

class AddRoleToUsers < ActiveRecord::Migration
  def change
    add_column :users, :role, :integer, default: 0

I also set the first declared status be the default as recommended in the documentation.

And that’s all there is to it! You can find more information in the Rails Edge Guides 4.1 Release Notes.

SSL Error (failed certificate) with Ruby, Rails and OSX

Outdated SSL certificate files could be the reason you’re getting the Ruby error:

OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed.

If you have RVM installed, you could try this to update your SSL certificates:

rvm osx-ssl-certs status all
rvm osx-ssl-certs update all

This didn’t work in my case, however.

Alternatively (and what ended up working for me), you can try following thoughtbot’s Rails development setup script for Mac OS X and download a bundle of CA Root Certificates from Mozilla (

# download cert.pem file for openssl
cd /usr/local/etc/openssl/certs/
sudo curl -O
sudo mv cacert.pem cert.pem
cd -
echo "
# cert.pem file for openssl 
export SSL_CERT_FILE=/usr/local/etc/openssl/certs/cert.pem" >> ~/.bash_profile
source ~/.bash_profile

How to check if a table is empty in Rails

You may already know that if you want to check for the existence of an Active Record object you can use a method called exists? Let’s say you have a User model and would like to know if a record exists with a matching primary id:

User.exists?(1)               # returns true if a user with matching id of 1 exists and false otherwise.
User.exists?(:name => 'John') # also works with find-style conditionals

It’s also possible to use exists? without any arguments on a model to see if the table is empty:

User.exists? # returns false if the users table is empty and true otherwise.

Additionally, you can use User.any? and User.many? instead of exists? to check for existence on a model or relation.