views:

928

answers:

5

I'm looking for an easiest way how to implement the "suggest" feature for a text entry field in a Rails application. The idea is to complete names stored in a database column, giving the user a drop-down menu of possible matches as he types.

Thanks for any suggestions!

+4  A: 

Ruby on Rails has the Prototype framework available. This framework is used by Script.aculo.us and it provides an autocompleter control that may provide the functionality that you're seeking.

Tom
A: 

EDIT: I'll leave this answer here as a sort of theoretical reference point, but it sounds like the autocompleter answer is likely to be more useful to you :)

Disclaimer: Although I work for Google (which clearly has "Suggest" elements in various UIs) I haven't looked at any of the code around this area, nor even spoken to anyone about the client-side aspect.

The server-side language is probably irrelevant here. The important bit is the AJAX required on the client side.

I suggest you have a timer of about 1 second (experiment to find a sweet spot) which is reset each time the user enters a keystroke into the textbox and cancelled if the user navigates away from the textbox. If the timer fires, make it fire an AJAX request. The AJAX request would contain what the user has typed so far. The AJAX response should be the list of suggestions and the original request text.

If, when the AJAX response returns, the text in the textbox is still the same as the field in the response (i.e. the user hasn't typed since) and if the textbox still has focus, then offer a dropdown. (There must be hundreds of example pages about HTML comboboxes to do this side of things.)

All the server needs to do is respond to the AJAX request by performing the search and formatting the response appropriately - that's a lot easier than the client side!

Hope that helps - sorry to not have any sample code, but I suspect it's quite involved and I'm not really a JavaScript developer.

Jon Skeet
A: 

As with most things in Rails there are several ways to do this. Rails used to include a set of auto-completion helpers built-in, but that functionality has now been removed to the auto_complete plugin. This is likely the easiest way for you to get what you want implemented - a simple command in the controller, some simple stuff in your view - ta-dah. To use this solution you'll just need to install the plugin into your app - see this page which tells you all you need to know to get it installed and to get started.

As noted in another answer, going this route will make use of the prototype and scriptaculous AJAX frameworks that come bundled with Rails. There are other AJAX frameworks, notably JQuery, that can also help you accomplish this functionality, but you'll have more ramp-up learning to use them than just going with the plugin.

Yardboy
A: 

You can also try this slightly more manual approach

# your_view.rhtml

<%= text_field 'contact', 'name', :id => 'suggest' %>
<div id='dropdown' style='display:none; z-index: 100; background: #FFFFFF'></div>

<script>
  new Ajax.Autocompleter('suggest', 'dropdown', "<%= url_for :controller => 'contacts', :action => 'suggest_name' %>") 
</script>

# contacts_controller.rb

def suggest_name
  query_string = params[:contact][:name]
  @contacts = Contact.find.all :conditions => ['name ilike ?', "%#{query_string}%"]
  render :partial => 'name_suggestions'
end

# contacts/_name_suggestions.rhtml

<ul>
<% for contact in @contacts %>
  <li><%= contact.name %></li>
<% end %>
</ul>
JasonOng
+5  A: 

Rails makes 'suggest'-style auto completion on text fields really easy using the text_field_with_auto_complete method.

In Rails 1.x this method was built into ActionView::Helpers::JavaScriptMacrosHelper, but for Rails 2.x it was moved to a separate plugin.

Let's say you have a model called Post which has a text field called title. In your view, where you would normally use text_field_tag (or f.text_field), just use text_field_with_auto_complete instead:

<%= text_field_with_auto_complete :post, :title %>

Additionally, in PostsController, you have to make a corresponding declaration:

class PostsController < ApplicationController
  auto_complete_for :post, :title
end

What this does behind the scenes is dynamically add an action called auto_complete_for_[object]_[method] to the controller. In the above example this action will be called auto_complete_for_post_title.

It's worth pointing out that the find call used by this auto-generated action will act across all model objects, e.g. Post.find(:all, ...). If this isn't the behaviour you want (for example, if want to restrict the search to a specific subset of Posts based on the logged in user) then you have to define your own auto_complete_for_[object]_[method] action in your controller.

Olly