In this the tutorial, we will review how to build a search form and then we'll look at how to implement a search form using ElasticSearch. I'll be using a book review app that I built recently.
I want to implement a search function that will allow users to search the database for a book that has been reviewed.
Basic Rails Search
In the app, a user can have more than one book review and a book review belongs to a user.
Let's look at what the respective models look like.
This is the book review model.
# frozen_string_literal: true
class BookReview < ApplicationRecord
belongs_to :user
end
This is the user model.
# frozen_string_literal: true
class User < ApplicationRecord
has_many :book_reviews
end
We'll have to work with the model, view and controller in this app.
The first thing we'll do is add the search function to our view. We'll be using the index view to add the search function.
Modifying the view
<%= form_with url: book_reviews_path, method: :get, local: true do |form| %>
<%= form.label :search, "Search Books:"%>
<%= form.text_field :search, id: :search, class: "form-control" %>
<br />
<%= form.submit "Submit", class: 'btn btn-primary'%>
<%end%>
This will create our search form and our controller is waiting to receive the params[:search] and that is set in the form.text_field.
Modifying the Book Review Model
The next thing we want to do is add the logic for our search to the model. The reason we are adding it to our model and not our controller is that it is good practice to keep your controllers lean and add logic to your models.
# frozen_string_literal: true
# BookReview Model with validations
class BookReview < ApplicationRecord
belongs_to :user
def self.search(search)
if search
book_reviews = BookReview.where('title LIKE ?', "%#{search}%")
if book_reviews.present?
where(id: book_reviews)
else
all
end
else
all
end
end
end
(I'm using Rails 5.1.7 and with this comes the ability to use all instead of typing BookReview.all)
Our search function will render on the index page. If there isn't a search parameter entered it will render all the books. It will also render all the books if the search doesn't find a match.
Now that we have seen how a basic search form is added to a rails project, let's look at what we can use that will allow us to scale and have a more efficient and robust search.
The current search we are using works well for a small project but large scale applications will need something else.
ElasticSearch
Elasticsearch is an open-source search and analytics engine. It uses a REST API that makes it easy to use.
It has multiple uses but for this blog and tutorial, were are going to use it as a search engine.
If you are using brew you can issue this command to install elasticsearch
brew install elasticsearch
To use elasticsearch in our rails app, we'll need to add this gem and run bundle install.
gem 'searchkick"
Then we need to add searchkick to the model that we would like to search. In our example, we would add it to your book_reviews model.
# frozen_string_literal: true
class BookReview < ApplicationRecord
searchkick
end
Then you'll want to add data to the search index.
rails searchkick:reindex CLASS=BookReview"
Type elasticsearch in the command line and then you can type
curl http://localhost:9200
in a separate window to make sure elasticsearch is up and running.
We don't need to make any changes to our index view, however, we will need to make changes to our model and controller.
Let's add the search logic to our model so that we are adhering to the design principle of fat models and skinny controllers.
def self.advanced_search(search_results)
if search_results
BookReview.search(search_results, fields: [:title])
else
all
end
Let's add this method to our controller
def index
@book_reviews = BookReview.advanced_search(params[:search])
end
This is all we need to do to add elasticsearch. ElasticSearch will yield results out-of-the-box even if the user hasn't spelled the word correctly.
ElasticSearch can do some much more but I hope this tutorial has given you the knowledge on how to add it to your rails application.
Top comments (3)
Thanks for sharing Aweys.
Elasticsearch is a solid start but using a third party like Algolia service could be better if you need to scale, distribute quickly, another benefit is search speed.
Resources to get a detailed comparison:
Hey Victor,
I appreciate the input and you taking the time to share this information.
I'll definitely check Algolia out.
You are welcome, mate. 👍