Forum: Ruby on Rails Can text_field_with_auto_complete return ID?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
47c4771d9d8782067b57faf3aed18a44?d=identicon&s=25 carlos.okada (Guest)
on 2005-11-29 18:31
(Received via mailing list)
Hello

Can I make text_field_with_auto_complete show the name atribute and then
return the ID of the selected object when the page is posted-back?

Thanks!

Okada.
5f32494d2d20052f8067a460e05977a5?d=identicon&s=25 Shai Shefer (Guest)
on 2006-06-06 17:22
I am having the same issue...

Can anyone help?
D0cd6b10e01bacb976b3b815a9c660bc?d=identicon&s=25 Alex Wayne (Guest)
on 2006-06-06 22:35
carlos.okada wrote:
> Hello
>
> Can I make text_field_with_auto_complete show the name atribute and then
> return the ID of the selected object when the page is posted-back?
>
> Thanks!
>
> Okada.

A textfield just returns it's contents.  It's just how HTML works.  What
you can do is match it up server side.

  object = SomeModel.find(:first,
                 :conditions => ['title = ?',
params[:data_from_textbox]])
A083f2c63fc0be7f8f19006c9dbdff86?d=identicon&s=25 Dale Martenson (dale)
on 2006-06-06 23:11
Shai Shefer wrote:
> I am having the same issue...
>
> Can anyone help?

The trick that I use is to return the id as a hidden field. Here is an
example of _full_names.rhtml I used as part of the Contacts demo I am
working on.

<ul class="full_names">
<% for contact in @contacts do -%>
  <li class="contact">
    <div class="id" style="display:none"><%= contact.id %></div>
    <div class="full_name" style="font-weight:bold"><%=h
"#{contact.first_name} #{contact.last_name}" %></div>
    <div class="address" style="font-size:smaller">
      <%=h "#{contact.address}" %><br>
      <%=h "#{contact.city}, #{contact.state} #{contact.zip_code}" %>
    </div>
  </li>
<% end -%>
</ul>

I then take the resulting value returned when the user clicks the
appropriate item and convert it to an integer which I can use to find
the correct Contact entry. Using this method I can then update multiple
fields.
A083f2c63fc0be7f8f19006c9dbdff86?d=identicon&s=25 Dale Martenson (dale)
on 2006-06-06 23:14
Alex Wayne wrote:
> carlos.okada wrote:
>> Hello
>>
>> Can I make text_field_with_auto_complete show the name atribute and then
>> return the ID of the selected object when the page is posted-back?
>>
>> Thanks!
>>
>> Okada.
>
> A textfield just returns it's contents.  It's just how HTML works.  What
> you can do is match it up server side.
>
>   object = SomeModel.find(:first,
>                  :conditions => ['title = ?',
> params[:data_from_textbox]])

This only works if the text contents returned are unique enough. If your
data is more complex or if you have multiple similar entries, this
doesn't work well.
5f32494d2d20052f8067a460e05977a5?d=identicon&s=25 Shai Shefer (Guest)
on 2006-06-07 18:28
Dale Martenson wrote:
>
> The trick that I use is to return the id as a hidden field. Here is an
> example of _full_names.rhtml I used as part of the Contacts demo I am
> working on.
>
> <ul class="full_names">
> <% for contact in @contacts do -%>
>   <li class="contact">
>     <div class="id" style="display:none"><%= contact.id %></div>
>     <div class="full_name" style="font-weight:bold"><%=h
> "#{contact.first_name} #{contact.last_name}" %></div>
>     <div class="address" style="font-size:smaller">
>       <%=h "#{contact.address}" %><br>
>       <%=h "#{contact.city}, #{contact.state} #{contact.zip_code}" %>
>     </div>
>   </li>
> <% end -%>
> </ul>
>
> I then take the resulting value returned when the user clicks the
> appropriate item and convert it to an integer which I can use to find
> the correct Contact entry. Using this method I can then update multiple
> fields.

I understand the concept and I tried out some code, but it does not seem
to work as in the example... Would you be able to post a little of your
controller and view code so I could compare and possibly see what I did
wrong?

To help better understand, Ill post mine as well...

I want to search for a product title and when I click "see" I want to go
to that products page..

In my view I have:

<%= start_form_tag :action => 'view', :id => @search_item %>

<%= text_field_with_auto_complete :product, :title, :size => 40 ,
:skip_style => true  %>

<%= end_form_tag %>

And then, in the Controller:

def auto_complete_for_product_title
  auto_complete_responder_for_products params[:title]
end

private

def auto_complete_responder_for_products(value)
  @search_results = Product.find(:all,
    :conditions => [ 'LOWER(title) LIKE ?',
    '%' + value.downcase + '%' ],
    :order => 'title ASC',
    :limit => 8)
  render :partial => 'products'
end

And in my partial:

<div class="auto_complete">
<ul>
<% for search_item in @search_results do -%>
  <li>
	<div class="id" style="display:none"><%= search_item.id %></div>
    <div class="image">
    	<%= image_tag url_for_file_column "search_item", "art", "50" -%>
    </div>
    <div class="title"><%= search_item.title %></div>
  </li>
<% end -%>
</ul>
</div>

Could anyone offer some insight as to what may be wrong? I will say that
when looking at the scriptaculous example I do get a bit confused with
the :message params that are passed... what are they needed for?

Thanks
A083f2c63fc0be7f8f19006c9dbdff86?d=identicon&s=25 Dale Martenson (dale)
on 2006-06-08 08:22
Shai Shefer wrote:
> Dale Martenson wrote:
>>
>> The trick that I use is to return the id as a hidden field. Here is an
>> example of _full_names.rhtml I used as part of the Contacts demo I am
>> working on.
>>
>> <ul class="full_names">
>> <% for contact in @contacts do -%>
>>   <li class="contact">
>>     <div class="id" style="display:none"><%= contact.id %></div>
>>     <div class="full_name" style="font-weight:bold"><%=h
>> "#{contact.first_name} #{contact.last_name}" %></div>
>>     <div class="address" style="font-size:smaller">
>>       <%=h "#{contact.address}" %><br>
>>       <%=h "#{contact.city}, #{contact.state} #{contact.zip_code}" %>
>>     </div>
>>   </li>
>> <% end -%>
>> </ul>
>>
>> I then take the resulting value returned when the user clicks the
>> appropriate item and convert it to an integer which I can use to find
>> the correct Contact entry. Using this method I can then update multiple
>> fields.
>
> I understand the concept and I tried out some code, but it does not seem
> to work as in the example... Would you be able to post a little of your
> controller and view code so I could compare and possibly see what I did
> wrong?
>

I posted a description of what I am doing on my blog. See if this helps,
if not I will create a demo Rails app for you to look at.

http://www.dalemartenson.com/blog/?p=24

Here is a the parts that I use to get the id of an object and update
multiple fiields.

index.rthml-------------------

<html>
  <head>
    <%= javascript_include_tag :defaults %>
  </head>
  <body>
    <p style="background-color:#d923d9;padding:20px;">Look-up Contact By
Full Name: <%= render :partial => 'get_full_name' %></p>
	<hr>
    <div>
      <%= render :partial => 'get_name_info' %>
      <%= render :partial => 'get_address_info' %>
      <%= render :partial => 'get_phone_info' %>
      <%= render :partial => 'get_internet_info' %>
    </div>
  </body>
</html>

EOF---------------------------

I like using render :partial for all the pieces of the displayed page.
The autocomplete field is in the _get_full_name.rthml partial.

_get_full_name.rhtml----------

<span id="full_name">
<%= text_field_with_auto_complete :contact, :full_name, {},
:after_update_element =>
  "function(element,value) " +
  "{ " +
    remote_function(:update=>'full_name',:url=>{:action=>:get_full_name},:with=>"'id='+element.value")
+ ";" +
    remote_function(:update=>'name_info',:url=>{:action=>:get_name_info},:with=>"'id='+element.value")
+ ";" +
    remote_function(:update=>'address_info',:url=>{:action=>:get_address_info},:with=>"'id='+element.value")
+ ";" +
    remote_function(:update=>'phone_info',:url=>{:action=>:get_phone_info},:with=>"'id='+element.value")
+ ";" +
    remote_function(:update=>'internet_info',:url=>{:action=>:get_internet_info},:with=>"'id='+element.value")
+ ";" +
  "}"
%>
</span>

EOF---------------------------

This uses the after_update_element to force the updating of other
corresponding pieces of the page being displayed. The id is past from
the element.value which is really a string based on list item contents
that were shown to the user. This generated Javascript function controls
getting the data for the updates and helps to perform the multiple
partial updates.

Note: I reference full_name as if it were a field in my contacts table,
but it isn't. I have added a member function to the Contacts model to
combine the first_name and last_name fields into a full_name.

  def full_name
    "#{self.first_name} #{self.last_name}"
  end

Since I want to perform full name searches using a single field, I
require a custom handler be added to my controller.

  def auto_complete_for_contact_full_name
    @contacts = Contact.find(:all,
      :conditions => [ 'LOWER(CONCAT(first_name," ",last_name)) LIKE ?',
      '%' + params[:contact][:full_name].downcase + '%' ],
      :order => 'first_name ASC',
      :limit => 8)
    render :partial => 'full_names'
  end

The list item content is controlled by the _full_names.rhtml partial in
this example.

_full_names.rhtml--------------

<ul class="full_names">
<% for contact in @contacts do -%>
  <li class="contact">
    <div class="id" style="display:none"><%= contact.id %></div>
    <div class="full_name" style="font-weight:bold"><%=h
"#{contact.first_name} #{contact.last_name}" %></div>
    <div class="address" style="font-size:smaller">
      <%=h "#{contact.address}" %><br>
      <%=h "#{contact.city}, #{contact.state} #{contact.zip_code}" %>
    </div>
  </li>
<% end -%>
</ul>

EOF---------------------------

Rather than just display a simple list of names. I display a bold full
name and a complete address in a small font to help uniquely identify
the individual. But the important part is what is not seen by the user.
The first part of my list item is a non-displayed text string of the
object id. This uniquely identifies the item without having to re-query
the database which can be problematic depending on the data uniqueness
of the data and if multiple entries may exist.

The string returned when the user selects an entry looks something like
"\n   123\n  Dale Martenson\n  1234 Blah Street\n  Somewhere, Someplace
12345". As you will see, I can take thing string and convert it to an
integer to 'steal' the first id portion while ignoring the rest. From
the generated Javascript above, this is the result in element.value that
I pass as a parameter back to my controller methods.

All the controller methods are very similar.

  def get_address_info
    @contact = Contact.find(params[:id].to_i)
    render :partial => 'get_address_info'
  end

As you can see, it takes the id parameter converts it to an integer and
finds the correct object based on the id. Then the corresponding partial
is rendered to complete the updating of that portion of the display.

_get_address_info.rhtml-------

<span id="address_info">
  <fieldset>
    <legend>Address Information</legend>
    Address: <%= text_field :contact, :address %><br>
    City: <%= text_field :contact, :city %>
    State: <%= text_field :contact, :state %>
    Zip: <%= text_field :contact, :zip_code %>
  </fieldset>
</span>

EOF---------------------------

There may be a more elegant way to do the update, but I have yet to
determine one. If anyone has any suggestions for improving this please
let me know.
E5addfb886fa24edf1fcf9473a9b5a34?d=identicon&s=25 Jeremy Maziarz (jmaziarz)
on 2009-12-31 20:53
I forked DHH's auto_complete plugin to add the record id to the id tag
of the <li> element. There is an example in the README of how to use the
id using :after_update_element. Check it out on GitHub at
http://github.com/jmaziarz/auto_complete.
This topic is locked and can not be replied to.