Today, we will learn how to implement Complex Search Term on Rails, also how to install Bootstrap with Bower and generate fake data with Faker gem.

Install new project with name “complex_search”-
$ rails new complex_search -d postgresql
Configure database.yml file inside config-
# config/database.yml
default: &default
adapter: postgresql
encoding: unicode
username: postgres # Based on your username
password: 123456 # Based on your password
# For details on connection pooling, see rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
Then open your command prompt & write below command for database migration-
$ cd complex_search
$ bundle exec rake db:create
$ bundle exec rake db:migrate
$ bundle exec rails server
Write localhost:3000 to your browser & will show below image-

We just completed the project setup, now needs to setup Bootstrap.
There are three ways to install Bootstrap into a Rails application: as a Ruby Gem, by referencing a publicly available version hosted on a CDN, or by downloading it and storing it within our application’s source.
We’re going to use that latter, assisted by a tool called Bower.
To install Bootstrap using Bower, we’ll first need to install Bower; then we’ll instruct it to download and install Bootstrap; and, finally, we’ll configure the asset pipeline to make Bootstrap available.
Install Bower
Bower itself as a package manager for the web. It was created by Twitter and is analogous to RubyGems, but manages front-end assets (including CSS frameworks like Bootstrap and JavaScript libraries like Angular). Bower is written in JavaScript, and so it requires a JavaScript runtime in order to work. That means you’ll have to install Node JS.
Once you have Node JS installed, you’ll have access to the npm command-line application. This is a package manager for JavaScript, and we’ll use that to install Bower.
$ npm install -g bower
Then-
# complex_search/Gemfile
gem 'bower-rails'
We can install with bundler.
$ bundle install
We have to create Bowerfile file in the root directory then install Bootstrap.
# complex_search/Bowerfile
asset 'bootstrap-sass-official'
Then-
$ bundle exec rake bower:install
Add bootstrap to our asset pipeline
# complex_search/app/assets/stylsheet/application.css
/*
*= require_tree.
*= require_self
➤ *= require 'bootstrap-sass-official'
*/
We are just done with installing Bootstrap with Bower!
Now we will generate a model called Customer for implementing complex search term-
$ rails generate model Customer first_name:string last_name:string email:string username:string
The migration file created & look like below-
# complex_search/db/migrate/timestamps_create_customers.rb
class CreateCustomers < ActiveRecord::Migration[5.0]
def change
create_table :customers do |t|
t.string :first_name, null: false
t.string :last_name, null: false
t.string :email, null: false
t.string :username, null: false
t.timestamps null: false
end
add_index :customers, :email, unique: true
add_index :customers, :username, unique: true
end
end
Then execute following command-
$ rake db:migrate
This will create a “customers” table in database, now generate fake data for implementing search query.
Adding faker gem-
# complex_search/Gemfile
gem 'faker'
Then, we’ll install it the gem-
$ bundle install
After that-
# complex_search/db/seeds.rb
500.times do |i|
Customer.create!(
first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
username: "#{Faker::Internet.user_name}#{i}",
email: Faker::Internet.user_name + i.to_s + "@#{Faker::Internet.domain_name}")
end
Then execute the above code-
$ bundle exec rake db:seed
We just created 500 fake data (rows) in database!
Building the search UI
$ rails generate controller customers index
# complex_search/config.routes.rb
resources :customers, only: [:index]
# complex_search/app/controller/customers_controller.rb
class CustomersController < ApplicationController
def index
@customers = Customer.all.limit(10)
end
end
# complex_search/app/views/customers/index.html.erb
<h1>Customer Search</h1>
<section class="search-form">
<%= form_for :customers, method: :get do |f| %>
<div class="input-group input-group lg">
<%= label_tag :keywords, nil, class: "sr-only" %>
<%= text_field_tag :keywords, nil, placeholder: "First Name, Last Name, or Email Address", class: "form-control input-lg" %>
<span class="input-group-btn">
<%= submit_tag "Find Customers", class: "btn btn-primary btn-lg" %>
</span>
</div>
<% end %>
</section>
<section class="search-results">
<h1 class="h3">Results</h1>
<ol class="list-group">
<% @customers.each do |customer| %>
<li class="list-group-item clearfix">
<h3 class="pull-right">
<small class="text-uppercase">Joined</small>
<%= l customer.created_at.to_date %>
</h3>
<h2 class="h3">
<%= customer.first_name %> <%= customer.last_name %>
<small><%= customer.username %></small>
</h2>
<h4><%= customer.email %></h4>
</li>
<% end %>
</ol>
</section>
Now create a file inside models called “customer_search_term.rb” and then write following code-
# complex_search/app/models/customer_search_term.rb
class CustomerSearchTerm
attr_reader :where_clause, :where_args, :order
def initialize(search_term)
search_term = search_term.downcase
@where_clause = ""
@where_args = {}
if search_term =~ /@/
build_for_email_search(search_term)
else
build_for_name_search(search_term)
end
end
def build_for_name_search(search_term)
@where_clause << case_insensitive_search(:first_name)
@where_args[:first_name] = start_with(search_term)
@where_clause << " OR #{case_insensitive_search(:last_name)}"
@where_args[:last_name] = start_with(search_term)
@order = "last_name asc"
end
def build_for_email_search(search_term)
@where_clause << case_insensitive_search(:first_name)
@where_args[:first_name] = start_with(extract_name(search_term))
@where_clause << " OR #{case_insensitive_search(:last_name)}"
@where_args[:last_name] = start_with(extract_name(search_term))
@where_clause << " OR #{case_insensitive_search(:email)}"
@where_args[:email] = search_term
@order = "lower(email) = " + ActiveRecord::Base.connection.quote(search_term) + "desc, last_name asc"
end
def start_with(search_term)
search_term + "%"
end
def case_insensitive_search(field_name)
"lower(#{field_name}) like :#{field_name}"
end
def extract_name(email)
email.gsub(/@.*$/,'').gsub(/[0-9]+/,'')
end
end
Then modify code in controller file-
# complex_search/app/controllers/customers_controller.erb
class CustomersController < ApplicationController
PAGE_SIZE = 10
def index
if params[:keywords].present?
@keywords = params[:keywords]
customer_search_term = CustomerSearchTerm.new(@keywords)
@customers = Customer.where(customer_search_term.where_clause, customer_search_term.where_args).order(customer_search_term.order)
else
@customers = []
end
end
end
And that’s all! We have implemented a full & complex search feature on the Rails project.
Happy coding 🙂