Adding search to your system is somewhere between super easy and “let’s hire a team”. Let’s look at the first tiers of difficulty.
Adding simple search of a single model can be achieved using the Rails basics: create a form, and filter in the controller:
<!-- global search form -->
<%= form_with url: global_search_path do |form| %>
<%= form.search_field :q, value: params[:q] %>
<% end %>
<!-- app/views/global_searches/show.html.erb -->
<%= render @results %>
# config/routes.rb
Rails.application.routes.draw do
resource :global_search, only: :show
end
# app/controllers/global_searches_controller.rb
class GlobalSearchesController < ApplicationController
def show
search = "%#{params[:q].to_s.downcase}%"
@results = MyModel.where("my_models.title LIKE ?", search)
end
end
This will do a case insensitive search across a single field on a single model.
PostgreSQL has several native full text search options. The pg_search gem makes it easy to start using them in our Rails app. Building on the previous search, we will add the gem, build a search scope, and use that scope:
# Gemfile
gem "pg_search"
# app/models/my_model.rb
class MyModel < ApplicationRecord
include PgSearch::Model
has_rich_text :body
pg_search_scope :search_content,
against: [ :title, :description ],
associated_against: {
rich_text_body: [ :body ]
},
using: {
tsearch: {
any_word: true, # any matching word will match
dictionary: "english", # match jump/jumped/jumping
prefix: true # cat matches caterpillar
}
}
end
# app/controllers/global_searches_controller.rb
class GlobalSearchesController < ApplicationController
def show
search = params[:q]
@results = MyModel.search_content(search)
end
end
With this in place we can search, including similar works, on multiple fields, of a single model. Using the associated against will also search on fields of an associated model, and ActiveText body in this case.
Tune in tomorrow as we expand this search to multiple models making it perfect for a global search.