Getting started with Ruby on Rails and Bonsai Elasticsearch is fast and easy. In this guide, we will start with a very basic Ruby on Rails application and add the bare minimum amount of code needed to support basic search with Elasticsearch. Users looking for more details and advanced usage should consult the resources at the end of this page.
Throughout this guide, you will see some code examples. These code examples are drawn from a very simple Ruby on Rails application, and are designed to offer some real-world, working code that new users will find useful. The complete demo app can be found in this GitHub repo.
Warning
SearchKick uses the official Elasticsearch Ruby client, which is not supported on Bonsai after version 7.13. This is due to a change introduced in the 7.14 release of the gem. This change prevents the Ruby client from communicating with open-sourced versions of Elasticsearch 7.x, as well as any version of OpenSearch. The table below indicates compatibility:
Engine | Version | Highest Compatible Gem Version |
Elasticsearch | 5.x | 7.13 |
Elasticsearch | 6.x | 7.14+ ( sic) |
Elasticsearch | 7.x | 7.13 |
OpenSearch | 1.x | 7.13 |
If you are receiving a
Elasticsearch::UnsupportedProductError
, then you'll need to ensure you're using a supported version of the Elasticsearch Ruby client.
Note
In this example, we are going to connect to Elasticsearch using the Searchkick gem. There are also the official Elasticsearch gems for Rails, which are covered in another set of documentation.
Step 1: Spin up a Bonsai Cluster
Make sure that there is a Bonsai Elasticsearch cluster ready for your app to interact with. This needs to be set up first so you know which version of the gems you need to install; Bonsai supports a large number of Elasticsearch versions, and the gems need to correspond to the version of Elasticsearch you’re running.
Bonsai clusters can be created in a few different ways, and the documentation for each path varies. If you need help creating your cluster, check out the link that pertains to your situation:
- If you’ve signed up with us at bonsai.io, you will want to follow the directions here.
- Heroku users should follow these directions.
The Cluster URL
When you have successfully created your cluster, it will be given a semi-random URL called the Elasticsearch Access URL. You can find this in the Cluster Overview, in the Credentials tab:
Heroku users will also have a
BONSAI_URL
environment variable created when Bonsai is added to the application. This variable will contain the fully-qualified URL to the cluster.
Step 2: Confirm the Version of Elasticsearch Your Cluster is On
When you have a Bonsai Elasticsearch cluster, there are a few ways to check the version that it is running. These are outlined below:
Option 1: Via the Cluster Dashboard Details
The easiest is to simply get it from the Cluster Dashboard. When you view your cluster overview in Bonsai UI, you will see some details which include the version of Elasticsearch the cluster is running:
Option 2: Interactive Console
You can also use the Interactive Console. In the Cluster Dashboard, click on the Console tab. It will load a default view, which includes the version of Elasticsearch. The version of Elasticsearch is called “number” in the JSON response:
Option 3: Using a Browser or
curl
You can copy/paste your
cluster URL into a browser or into a tool like curl
. Either way, you will get a response like so:
curl https://abcd123:efg456@my-cluster-123456.us-west-2.bonsaisearch.net:443 { "name" : "ip-172-31-14-16", "cluster_name" : "elasticsearch", "cluster_uuid" : "jVJrINr5R5GVVXHGcRhMdA", "version" : { "number" : "7.2.0", "build_flavor" : "oss", "build_type" : "tar", "build_hash" : "508c38a", "build_date" : "2019-06-20T15:54:18.811730Z", "build_snapshot" : false, "lucene_version" : "8.0.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" }
The version of Elasticsearch is called “number” in the JSON response.
Step 3: Install the Gem
To install Searchkick, you will need the searchkick gem. Add the following to your Gemfile outside of any blocks:
gem 'searchkick'
This will install the gem for the latest major version of Elasticsearch. If you have an older version of Elasticsearch, then you should follow this table:
Elasticsearch Version
|
Searchkick Version
|
|
1.x
|
→
|
1.5.1
|
2.x
|
→
|
2.5.0
|
5.x
|
→
|
3.1.3 (
additional notes)
|
6.x and up
|
→
|
4.0 and up
|
If you need a specific version of Searchkick to accommodate your Elasticsearch cluster, you can specify it in your Gemfile like so:
gem 'searchkick', '3.1.3' # For Elasticsearch 5.x
Once the gem has been added to your Gemfile, run
bundle install
.
Step 4: Add Searchkick to Your Models
Any model that you will want to be searchable with Elasticsearch will need to be configured to do so by adding the
searchkick
keyword to it.
For example, our demo app has a User model that looks something like this:
class User < ApplicationRecord searchkick end
class User < ApplicationRecord searchkick settings: { number_of_replicas: 0 } end
If you have questions about shards and how many is enough, check out our Shard Primer and our documentation on Capacity Planning.
Step 5: Create a Search Route
You will need to set up a route to handle searching. The easiest way to do this with Searchkick is to have a search route per model. This involves updating your models’ corresponding controller, and defining routes in
config/routes.rb
. You’ll also need to have some views that handle rendering the results, and a form that posts data to the controller(s). Take a look at how we implemented this in our demo app for some examples of how this is done:
Our Example
In our example Rails app, we have one model,
User
, with searchkick
. It looks something like this:
class User < ApplicationRecord searchkick end
To implement search, we updated the file
app/controllers/users_controller.rb
and added this code:
class UsersController< ApplicationController #... a bunch of controller actions, removed for brevity def search @results = User.search(params[:q]) end #... more controller actions removed for brevity end
We then created a route in the
config/routes.rb
file:
Rails.application.routes.draw do resources :users do collection do post :search # creates a route called users_search end end end
Next, we need to have some views to render the data we get back from Elasticsearch. The
search
controller action will be rendered by creating a file called app/views/users/search.html.erb
and adding:
Search Results
<% if @results.present? %> <%= render partial: 'search_result', collection: @results, as: :result %> <% else %>Nothing here, chief!
<% end %>
This way if there are no results to show, we simply put a banner indicating as such. If there are results to display, we will iterate over the collection (assigning each one to a local variable called
result
), and passing it off to a partial. We also created a file for a partial called app/views/users/_search_result.html.erb
and added:
<%= link_to "#{result.first_name} #{result.last_name} <#{result.email}>", user_path(result) %>
<%= result.company %>
<%= result.company_description %>
This partial simply renders a search result using some of the data of the matching ActiveRecord objects.
At this point, the
User
model is configured for searching in Elasticsearch, and has routes for sending a query to Elasticsearch. The next step is to render a form so that a user can actually use this feature. This is possible with a basic form_with
helper.
In this demo app, we added this to the navigation bar:
<%= form_with(url: "/search", method: "post", class: 'form-inline my-2 my-lg-0', local: true) do %> <%= text_field_tag(:q, nil, class: "form-control mr-sm-2", placeholder: "Search") %> <%= button_tag("Search", class: "btn btn-outline-info my-2 my-sm-0", name: nil) %> <% end %>
This code renders a form that looks like this:
Please note that these classes use Bootstrap, which may not be in use with your application. The ERB scaffold should be easily adapted to your purposes.
We’re close to finishing up. We just need to tell the app where the Bonsai cluster is located, then push our data into that cluster.
Step 6: Tell Searchkick Where Your Cluster is Located
ELASTICSEARCH_URL
, and if it doesn’t find it, it uses
localhost:9200
. This is a problem because your Bonsai cluster is not running on a localhost. We need to make sure Searchkick is pointed to the correct URL.
BONSAI_URL
set in your application environment that points at your Bonsai cluster URL.
# Substitute with your cluster URL, obviously: export BONSAI_URL="https://abcd123:efg456@my-cluster-123456.us-west-2.bonsaisearch.net:443"
Writing an Initializer
You will only need to write an initializer if:
- You are not using the bonsai-searchkick gem for some reason, OR
- You are not able to set the
BONSAI_URL
environment variable in your application environment
If you need to do this, then you can create a file called
config/initializers/elasticsearch.rb
. Inside this file, you will want to put something like this:
# Assuming you can set the BONSAI_URL variable: ENV["ELASTICSEARCH_URL"] = ENV['BONSAI_URL']
If you’re one of the few who can’t set the
BONSAI_URL
variable, then you’ll need to do something like this:
# Use your personal URL, not this made-up one: ENV["ELASTICSEARCH_URL"] = "https://abcd123:efg456@my-cluster-123456.us-west-2.bonsaisearch.net:443"
Step 7: Push Data into Elasticsearch
.reindex
. So if you want to reindex a model called
User
, you would run
User.reindex
.
User
model, you could run:
bundle exec rake searchkick:reindex CLASS=User
. Alternatively, if you have multiple Searchkick-enabled models, you could run
rake searchkick:reindex:all
.
User
model in a development environment might result in an index called
users_development_20191029111649033
. This allows Searchkick to provide zero-downtime updates to settings and mappings.
Step 8: Put it All Together
At this point you should have all of the pieces you need to search your data using Searchkick. In our demo app, we have this simple list of users:
This search box is rendered by a form that will pass the query to the
UsersController#search
action, via the route set up in config/routes.rb
:
UsersController#search
action, where it will be passed to Searchkick, which queries Elasticsearch. Elasticsearch will search the
users_development_20191029111649033
index, and return any hits to a class variable called
@results
.
UsersController
will then ensure the appropriate views are rendered. Each result will be rendered by the partial
app/views/users/_search_result.html.erb
. It looks something like this:
Congratulations! You have implemented Searchkick in Rails!