jQuery Autocomplete and Rails

This is an example of how I used the jQuery Automcomplete Widget with Rails 3.2 for a recipe search field. Some of the jQuery stuff mentioned below is included out of the box with a new Rails application.

  • Make sure the jQuery gem is referenced in the Gemfile
gem 'jquery-rails'
  • Include the jQuery javascripts in app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery-ui
  • Download one of the jQuery-ui css files, or a custom one, and put it in one of you asset locations. I put mine in vendor/assets/stylesheets/jquery-ui-1.8.18.custom.css. Include the css file in app/assets/stylesheets/application.css
*= require jquery-ui-1.8.18.custom.css
  • Create a controller action to search and return values for the autocomplete dropdown menu. In my Recipes controller (you could also create a seperate Search controller), I created an Action to return a list of matching recipe titles as a json array. The search can also be applied to recipes in a single category, hence the category_id parameter.
def search_on_title
    # search_on_title is a method on the model to do a wildcard search on keyword
    recipes = Recipe.search_on_title(params[:term], params[:category_id])
    render json: recipes.map(&:title)
  • Add a route for the search_on_title action.
resources :recipes do
    get 'search_on_title', :on => :collection
  • The search form is just a normal form.
<%= form_tag '', :method => :get do %>
    <%= search_field_tag :term, params[:term], :class=> "input-large" %>
    <%= submit_tag "Filter", :name => nil, :class => 'button btn', :id => "search_bn" %>
  <% end %>         
  • The javascript to hook up the autocomplete functionality looks like this. Notice the extra parameter to the source url – that’s how you would pass multiple values to your filter.
    source: '<%=search_on_title_recipes_path%>?category_id=<%=params[:category_id]%>',
    minLength: 2, delay: 500

There’s also a Rails gem to make autocomplete easier, but I found this to be easy enough such that I didn’t have to depend on an additional plugin.