Search Feature using Postgres 9.6.2 and Rails 5.1

In this article, you will learn how to implement search feature using pg_search gem in Rails 5.1 and Postgresql 9.6.2.

Install Postgres on Mac OS

I am on Mac OS 10.10.5, to install Postgres:

brew install postgres

To run postgres as a service install services:

brew tap homebrew/services

You can start the postgres server:

brew services start postgresql

To stop:

brew services stop postgresql

To restart:

brew services restart postgresql

Install the pg gem:

gem install pg -- --with-pg-config=/usr/local/bin/pg_config

To check the Postgres version:

pg_config --version

Search Feature using pg_search Gem

Create a new Rails 5.1 project.

rails new acomp --database=postgresql

Add the dotenv-rails gem to the development group in the Gemfile.

gem 'dotenv-rails'

Run bundle.

Create .env file in the Rails app root directory and specify the database user name and password.

PG_USER: 'db user'
PG_PASS: 'db password'

Add .env file to the .gitignore file so that it does not get checked in to git. Change the database.yml to use these environment variables for user and password.

development:
  adapter: postgresql
  encoding: unicode
  database: myapp_dev
  pool: 5
  username: <%= ENV['PG_USER'] %>
  password: <%= ENV['PG_PASS'] %>

test:
  adapter: postgresql
  encoding: unicode
  database: myapp_test
  pool: 5
  username: test
  password:

Create a user model:

rails g model user name surname

Migrate the database.

rails db:migrate

Add faker gem to the development group of the Gemfile.

gem 'faker'

Run bundle to install the gem. In the seeds.rb we can use the faker gem to populate the database with some records.

50.times do
  User.create({name: Faker::Name.first_name,
              surname: Faker::Name.last_name})
end

Populate the database:

rails db:seed

Define the routes:

resources :users, only: [:index]
root to: 'users#index'

Generate a users controller with index action:

rails g controller users index

Implement the index action:

class UsersController < ApplicationController
  def index
    @users = User.all
  end
end

The index page:

<ul>
  <%= render @users %>
</ul>

Create the user partial:

<li>
  <%= user.name %> <%= user.surname %>
</li>

Let's add the search form to the users index page:

<%= form_tag users_path, method: :get do %>
  <%= text_field_tag 'term', params[:term], placeholder: "Enter user's name or surname" %>
  <%= submit_tag 'Search' %>
<% end %>

Add the pg_search gem to Gemfile.

gem 'pg_search'

Run bundle.

Add the search method to the user model:

include PgSearch
pg_search_scope :search_by_full_name, against: [:name, :surname]

Change the users index action:

@users = if params[:term]
  User.search_by_full_name(params[:term])
else
  User.all
end

The search will now work. To implement partial search, change the user model:

pg_search_scope :search_by_full_name, against: [:name, :surname],
    using: {
      tsearch: {
        prefix: true
      }
    }

Now you search users by providing part of their name or surname.

Match Multiple Words

pg_search_scope :search_by_full_name, against: :name, using: { tsearch: { any_word: true } }

Search for all records that contains the term (separated by spaces) in the first name.

Weighting

pg_search_scope :search_by_full_name, against: { name: 'A', surname: 'B' }

Rank first name higher than surname in the search results. You can download the source code for this article from sgres.

References


Related Articles

Watch this Article as Screencast

You can watch this as a screencast Search Feature using Postgres 9.6.2 and Rails 5.1