Wolfmans Howlings

A programmers Blog about Ruby, Rails and a few other issues

Getting a record id from text_field_with_auto_complete

Posted by Jim Morris Mon, 23 Oct 2006 20:58:46 GMT

I ran into this problem a few times,and I have seen others asking the same question, if you use text_field_with_auto_complete and the selection list returns non-unique results, how do you reference the actual record in the database you want?

For instance if you have text_field_with_auto_complete :customer, :name then in your controller: name= params[:customer][:name] and Customer.find_all_by_name(name) returns more than one entry you need to be a little more tricky to retrieve the actual record you wanted to select.

There are a couple of ways to do it.

One method is mentioned here:

http://www.dalemartenson.com/blog/?p=24 which hides the id field being returned.

Another method is here http://ricardo.pacheco.name/blog/articles/2006/09 which uses javascript to write the id into a hidden_field.

This wiki entry (about half way down) suggests another way to do it, putting the id in the id tag of the <li> andf fetching it with javascript.

Another method I use is to put in the text_field a string like "23,Blogs,Fred", this is the id of the customer record, and the last,first name. Then I do this in the controller method that receives the form data (eg def create) ...

namecsv= params[:customer][:name]
id,last,first= namecsv.split(',')
customer= Customer.find(id)

Although in reality I usually write a setter in the Model to handle the csv so I can simply pass the entire params to the model ie Customer.new(params)

I get the namecsv in the text box using this partial for the auto completer...

<ul class="auto_complete">
<% for customer in @customers do -%>
   <li class="big">
     <div class="name"><%=h customer.fullname -%></div>
     <div class="code"><%=h "#{customer.id},#{customer.lname},#{customer.fname}" -%></div>
     <div class="email">
       <span class="informal"><%=h "#{customer.email}" -%></span>
     </div>
   </li>
<% end -%>
</ul>

using this in the view...

<% text_field_with_auto_complete( :customer, :name, {}, {:select => 'code', :skip_style => true) %>

Notice the :select => 'code', this is critical as it tells it which part of the popup list to put into the text_field.

This is a little ugly and error prone so you need some error checking etc. The other method looks nicer on the screen but is more work in the background.

Posted in  | Tags ,  | 1 comment | no trackbacks

Having multiple text_field_with_auto_complete in the same view

Posted by Jim Morris Wed, 18 Oct 2006 06:45:47 GMT

I ran into a problem using text_field_with_auto_complete in a view where I wanted to have many of them created by an iteration. You can use the :index option for the text_field, but it doesn't carry over to the various divs used in the AJAX calls.

<% 0.upto(10) do |legi|  %>
<% @leg= @mission.legs.find(:first, :conditions => ['legnum = ?', legi]) %>
text_field_with_auto_complete( :leg, :name, {:index => legi, :size => 20})
<% end %>
<% end %>

is what you really want to do, just as for a regular text_field.

I googled around and found this bug report for a fix to text_field_with_auto_complete that allows :index, as that fix does not appear to be in the current stable release of Rails or on Edge rails, I just created a my_text_field_with_auto_complete and it worked like a charm!!

  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

So I put this in app/helpers/application_helper.rb and simply use my_text_field_with_auto_complete in my views.

Here is what the controller side looks like...

  def auto_complete_for_leg_name
    leg= params[:leg].keys[0] # get index as its always only one at a time
    auto_complete_responder_for_name params[:leg][leg][:name]
  end
...
private
  def auto_complete_responder_for_name(value)
    param= value.downcase + '%'
    find_options= {
      :conditions => [ 'LOWER(lname) LIKE ?', param ],
      :order => 'lname ASC',
      :limit => 6
    }
    @names = Person.find(:all, find_options)
    render :partial => 'names'
  end

Posted in  | Tags ,  | 18 comments | no trackbacks