Ruby on Rails with text_field_with_auto_complete

I spent some time trying to figure out how to get a little text field with auto complete in Rails. Now I wanted many fields to have the same suggestions in one form. So here are some code samples. For some information. I have a model that is called Locations, basically this is just a collection of names of cities a person should be able to travel to.
In my controller I need

# The first value is the model the second the name of the field

auto_complete_for :location, :name

# As of rails version > 2.0 forgery protection is activated by default. As the
# AJAX stuff won't work otherwise you have to disable it for one method

protect_from_forgery :except => [:auto_complete_for_location_name]

# This is the method called my the AJAX obj
def auto_complete_for_location_name
leg= params[:location].keys[0] # get index as its always only one at a time

auto_complete_responder_for_name params[:location][leg][:name]
end

# This does the real magic. It queries the database and then renders a
# partial 'names' with the list of values to display. With some sql knowledge

# you should be able to understand the query
private
def auto_complete_responder_for_name(value)
param= '%' + value.downcase + '%'
find_options= {
:conditions => [ 'LOWER(name) LIKE ?', param ],
:order => 'name ASC',
:limit => 10
}
@names = Location.find(:all, find_options)
render :partial => 'names'

end

So that is for the controller. Now we need to create the partial. You can call this what ever you want but for now I called it names. So you need a file named '_names'

<ul class="autocomplete_list">
<% for name in @names -%>
<li class="autocomplete_item"><%= name.name %> </li>
<% end -%>
</ul>


This is quite simple it get's the array @names we built in the controller and builds an unordered list out of the elements.

Next we have to add a little helper method to the app/helpers/application_helper.rb file. This is basically the wrapper for the 'real' auto_complete_field.

# Methods added to this helper will be available to all templates in the application.

module ApplicationHelper

def my_text_field_with_auto_complete(object, method, tag_options = {}, completion_options = {})
if(tag_options[:index])
tag_name = "#{object}_#{tag_options[:index]}_#{method}"

else
tag_name = "#{object}_#{method}"
end

(completion_options[:skip_style] ? "" : auto_complete_stylesheet) +
text_field(object, method, tag_options) +
content_tag("div", "", :id => tag_name + "_auto_complete", :class => "auto_complete") +
auto_complete_field(tag_name, { :url => { :action => "auto_complete_for_#{object}_#{method}" } }.update(completion_options))
end

end

So now we should have everything that is needed to create our little textbox. Now in the view you just add
<%= my_text_field_with_auto_complete :location, :name, {:index => '1'} %>
And you increment the index value for every new field you add in that view.

Thank you to Wolfmans Howlings for posting all this.
http://blog.wolfman.com/articles/2006/10/17/having-multiple-text_field_with_auto_complete-in-the-same-view
http://wiki.rubyonrails.org/rails/pages/How+to+use+text_field_with_auto_complete

2 comments:

elgocho said...

Hello!!
I'm trying to do the auto_complete example but I can't make it work, I have a question. I have to created a style sheet with any name? I put all the code together but it doesn't show anything, I'm working with (rails (2.1.1, 2.1.0)). If you can help please!!! sorry for my English!!

Ribalba said...

Hey I can't find your email. Just send me one, you can find it on www.ribalba.de