BinaryWebPark

How To Setup jQuery Autocomplete With Elasticsearch In Your Rails Application

September 06, 2014

What is jQuery autocomplete?

The jQuery autocomplete plugin enables your users to receive suggestions while they type keywords in an input field.

How do you use it with elasticsearch?

If you haven’t setup elasticsearch with your Rails application, you can read about how to do it in these articles:

Step 1 – Install rails gem

Add the jquery-ui-rails to your Gemfile and run bundle install.

gem 'jquery-ui-rails'

At the command line type:

bundle install

Step 2 – Require the correct assets in your asset pipeline

Here I will show how I have my assets setup, but you can see the jquery-ui-rails README on github if you want to pick and choose what parts of jquery-ui you want to include.

In your application.css file, include the following assets:

//= require jquery-ui/core
//= require jquery-ui/theme

*= require_self

In your application.js file, include the following:

//= require jquery
//= require jquery_ujs
//= require jquery-ui

//= require_tree .

Step 3 – Write a controller method

class AjaxController < ApplicationController

  respond_to :json

  def autocomplete

  # ...

    @response = HTTParty.get("http://scctsi-ctds-staging.herokuapp.com/1/clinical\_trials/layman\_terms")

     @tag_counts = @response["response"] if params[:term] @tag_counts = @tag_counts.select { |term, value| term=~/#{params[:term]}.\*/}

    respond_with(@tag_counts)

  end

end

In the controller above, I am calling out to an API (basically another Rails application) that returns a JSON response with a disease name and a count like the following:

{"response":{"Kidney (Renal Cell) Cancer":6,"Advanced or

Metastatic":4,"Localized or Resected":4,"Heart Attack":17,"Rheumatic

Diseases":16,"Alzheimer&#8217;s Disease":8,"Dementia":6,"HIV":2,"AIDS":2,"Hepatitis c":2,"HIV and

aging":2,"HIV/hepatitis c co-infection":2,"Bladder (Urothelial,

Transitional Cell) Cancer":4,"Aneurysm":2,"Stroke":2,"Cerebrovascular

Disease":1,"Cerebrovascular Stroke":1,"Cerebrovascular Accident":1,"Skin

(Cutaneous) Cancer":3,"Squamous Cell":3,"Head and Neck

Cancers":1,"Hypopharynx":1,"Larynx":1,"Lip Nasopharynx":1,"Oral

Cavity":1,"Oropharynx":1,"Trachea":1,"Aortic Disease":3,"Aortic

Stenosis":5,"Heart Failure":7,"Heart Valve

Diseases":5,"Uterine/Endometrial Cancer":5,"Metastatic or

Unresectable":2,"Resectable (Pre-Cystectomy)":2,"Superficial

(Non-Invasive)":2,"Bone Cancer":5,"Ewing&#8217;s

Sarcoma":5,"Osteosarcoma":5,"Non-Small Cell Cancer (NSCLC)":6,"Small

Cell Lung Cancer (SCLC)":6,"Pancreatic

Cancer":2,"Narcolepsy":1,"Leukemia":5,"Acute Lymphoid leukemia

(ALL)":5,"Acute Myeloid Leukemia (AML)":5,"Acute Promyelocytic Leukemia

(APL)":5,"Chronic Lymphocytic Leukemia (CLL)":5,"Chronic Myelogenous

Leukemia (CML)":5,"Other Leukemia":5,"Lymphoma: Hodgkin":4,"Lymphomas:

Non-Hodgkin":4,"Cutaneous Lymphoma":4,"Diffuse Large B-Cell

Lymphoma":4,"Low Grade Lymphoma":4,"Mantle Cell Lymphoma":4,"Other

Histologies":4,"T-Cell Lymphoma":4,"Waldenstrom

Macroglobulinemia":4,"Gynecologic Cancers":2,"Eye Cancer":1,"High Blood

Pressure / Hypertension":2,"Pulmonary Hypertension":1,"Basal Cell

Carcinoma":1,"Melanoma":1,"Other Skin Cancers":1,"Multiple

Sclerosis":2,"Glaucoma":1,"Arrhythmias":1,"Atherosclerosis":2,"Thrombosis":1,"Arthritis":2,"Liver":3,"Ovarian/Peritoneal/Fallopian

Cancer":1,"Neuroendocrine Tumors":5,"Diabetes":2,"Huntington&#8217;s

Disease":16,"Parkinson&#8217;s Disease":16,"Tourette&#8217;s Disorder":13,"Brain

(Central Nervous System) Cancers":15,"Gliomas":16,"Metastatic

CNS":13,"Pediatric Brain Tumors":13,"Central Nervous System

Cancer":15,"Liver Tumors":7,"Chronic Liver Disease / Cirrhosis":7,"Any

Cancer Condition or Solid Tumor":57,"Breast Cancer":19,"Lung

Cancer":18,"Stomach Cancer":19,"Gastric (Stomach)

Cancer":7,"Gastrointestinal Stromal Tumor (GIST)":7,"Colon/Rectal

Cancer":6,"Anal Cancer":6,"Colon Cancer":6,"Rectal Cancer":6,"Prostate

Cancer":4,"Localized Disease":4,"Metastatic Disease":4}}

The params[:term] tells the controller what term(s) (or disease name(s)) to display to the end user in the autocomplete search box. It works in real-time.

Step 4 – Include a route to the controller in routes.rb

get 'autocomplete', to: 'ajax#autocomplete'

Step 5 – Write a coffeescript method to call the search method

In my case, I wanted to display the count along with the disease name asthe user typed their search term. I also wanted the user to be able to mouse click on the terms as they were dropping down via autocomplete and have the Rails application respond to that event by bringing the user to a page with more information about that term. Hence, I tell the autocomplete widget to submit the form with the selected term value via the select api method of jQuery autcomplete.

jQuery ->
  $('#search_terms').autocomplete
    source: (request, response) ->
      $.ajax
        url: '/autocomplete.json'
        dataType: "json"
        data: { term: request.term }
        success: (data) ->
        objects = $.map(data, (v, i) ->
        label: i+" ("+v.toString()+")"
        value: i)
        response objects
  select: (event, ui) ->
    $("#search_terms").val(ui.item.value)
    $("#search-form").submit()

Step 6 – Setup the search form in your Rails view

You also have to setup the search form with the appropriate CSS id names that you reference in your coffeescript code. Below is what I used.

= form_tag(search_path, :method => "get", id: "search-form", class: "navbar-form navbar-left") do
= text_field_tag :search_terms, params[:search_terms], placeholder: "Search by Keyword", class: "form-control"
= submit_tag "Search", :name => nil, class: "btn btn-default"