auto complete

simple auto complete text field

Posted in blog on Mar 26. Tags: , , , ,

I have been working on understanding the text_field_with_auto_complete functionality in Ruby on Rails for a project I am currently working on. There seems to be two written tutorials on the subject and they were a little confusing. Here is my attempt to be more specific.

Goal:

While editing an address record I want to show the user a short list of available suburbs that match what they have begun typing into he text box; and allow them to pick the one they want to use. When they save the record, I only want to store the ID of the suburb they typed in, not the actual text.

Solution:

Install the auto_complete gem:

ruby script/plugin install git://github.com/rails/auto_complete.git

This didn’t work on the windows system I was using, so I ended up having to grab the ZIP file and copy the contents to the ‘vendor/plugins/auto_complete’ folder the above command created.

First of all add to the site.rb model so we can refer to the suburb_name as if it was a field in the sites table:

def <span style="color: #ff00ff;">suburb_name</span>
  <span style="color: #00ccff;">suburb.name</span> if <span style="color: #ff6600;">suburb_id</span>
end

def <span style="color: #ff00ff;">suburb_name</span>=(value)
  self.<span style="color: #ff6600;">suburb_id</span> = Suburb.find_by_name(<span style="color: #ff0000;">value.split(',')[0]</span>).<span style="color: #000000;">id</span> unless value.blank?
end

Update the sites/edit.html.erb view to do the auto_complete markup:

<p>
  <%= f.label :<span style="color: #ff6600;">suburb </span>%><br />
  <%= text_field_with_auto_complete <span style="color: #993366;">:site</span>, :<span style="color: #ff00ff;">suburb_name</span>, {}, :skip_style => false %>
</p>

Add an action to the sites_controller.rb so the auto_complete call(s) can get the short list:

def auto_complete_for_<span style="color: #cc99ff;">site</span>_<span style="color: #ff00ff;">suburb_name</span>()  
  <span style="color: #0000ff;">@suburbs</span> = Suburb.find(:all , :conditions=> "<span style="color: #33cccc;">name </span>like '%"+params[<span style="color: #993366;"><span style="color: #000000;">:</span><span style="color: #cc99ff;">site</span></span>][:<span style="color: #ff00ff;">suburb_name</span>].upcase+"%' and we_deliver_to=1")  
  render :partial => '<span style="color: #99cc00;">auto_complete_</span><span style="color: #ff00ff;">suburb_name</span>'
end

Finally, create the _auto_complete_suburb_name.html.erb partial in the views/sites folder, the smallest form of which is like this

<ul><% for suburb in <span style="color: #0000ff;">@suburbs</span> do %><li><%=h <span style="color: #00ccff;">suburb.name</span> %><span style="color: #ff0000;">, </span><%=h suburb.postcode %></li><% end %></ul>

Important stuff you should know

  • I have added highlighting to illustrate the important connections between names as you move between view/model/controller. If you change one, you need to make the same change in every other occurence.
  • The suburbs table has no duplicates across the [name] field and no commas in any name value.
  • The COMMA in the partial is vitally important, I use it to tell the difference between the name value and the rest of the information that I don’t care about (the postcode). Use your own unique seperator if you have comma’s in your data.
  • No spaces in the _auto_complete_suburb_name partial, if you format it nicely your selected result will have lots of extra spaces (you’ll see what I mean)
  • There is no error checking in this. If the user types in a junk suburb the current code will not handle it gracefully.