I recently wrote a simple rails app to let people record measurements (current and voltage) on for a given plate. Each plate can have many measurements and each measurement belongs to only one plate. I wanted to make it easy for people to enter the data and there might be a fair number of plates, so I didn’t want people to have to scroll down a long drop down menu to pick a plate. This seemed like an ideal situation to use autocomplete on. Basically, the home screen is just the new measurements path. So, putting in the measurements will be easy. I then wanted to have a text field for the plate name that has autocomplete enabled. As the user enters in information for each plate, a little drop down list will popup that users can use to pick the correct plate. And if it’s a new plate, it will automatically add it to the database.

I had avoided doing something like this for a long time because I knew it would require javascript and I know absolutely none. However, I recently subscribed to Railscasts and watched an episode on autocomplete (#102). It didn’t look too difficult and I gave it a try.

app/assets/javascripts/application.js<pre class=”brush: javascript> //= require jquery //= require jquery-ui //= require jquery_ujs //= require_tree . </pre>

Just had to add the jquery-ui line.

app/assets/javascripts/measurements.js.coffee

jQuery ->
    $('#measurement_plate_name').autocomplete
        source: $('#measurement_plate_name').data('autocomplete-source')

Note that coffeescript IS whitespace dependent. Not knowing that probably caused the most difficulty in the entire process. Each one of those tabs above are four spaces. I usually use tabs that are two spaces and it didn’t work.

app/models/measurement.rb

belongs_to :plate

attr_accessible :current, :voltage, :note, :plate_name
def plate_name
  plate.try(:name)
end

def plate_name=(name)
  self.plate = Plate.find_or_create_by_name(name) if name.present?
end

I’m creating a virtual attribute to use in the form to set the plate name.

app/views/measurements/new.html.erb

<%= form_for (@measurement), :url => create_measurement_path, :method => :post do |f| %>
  

<%= f.label :plate_name %> <%= f.text_field :plate_name, data: {autocomplete_source: Plate.order(:name).map(&:name)} %>

<%= f.label :current %> <%= f.text_field :current %>

<%= f.label :voltage %> <%= f.text_field :voltage %>

<%= f.label :note %>
<%= f.text_area :note, size: '30x5' %>

<%= f.submit 'Submit' %>

<% end %>

I deleted some extra stuff in my form (error checking, etc.) because this is the important stuff that needs to be there.

app/assets/stylesheets/measurements.css.scss

ul.ui-autocomplete {
  position: absolute;
  list-style: none;
  margin: 0;
  padding: 0;
  border: solid 1px #999;
  cursor: default;
  li {
    background-color: #FFF;
    border-top: solid 1px #DDD;
    margin: 0;
    padding: 0;
    a {
      color: #000;
      display: block;
      padding: 13px;
    }
    a.ui-state-hover, a.ui-state-active, a.ui-state-focus {
      background-color: #FFFCB2;
    }
  }
} 

I had a hard time getting highlighting to work on the drop down list that appears. I had to add the a.ui-state-focus (line 18) to the css given in the Railscast to get it to work. I would have posted that on the site, but you have to log in with a github account and it just seemed like a hassle.

That’s basically it.