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.
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!
This writeup saved my life – you covered the last missing gap in getting elasticsearch running in prod on Heroku. Thanks for sharing this!
WOW. Reading this 4 hours ago could have saved half my day! Thank you so much 🙂
i am using the searchkick gem
Alright, any specifics for Windows please?