Jonathan Bennett

Adding Search Without Complexity

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.

1. Simple Search

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.

2. Better Search via PostgreSQL

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.