While working on a small application for a friend of mine, I stumbled upon a particularly tricky problem. But first a few lines about my general setup:
Among other things, my application is managing Employees, each of which has_and_belongs_to_many Skills. My pretty straightforward EmployeesController offers the actions "new" and "edit", which display a form where the user can edit the employee record. The user is able to assign skills to an employee by using text fields, if a skill does not already exist, it is created on the fly when updating the employee record.
This part of the application already works, I implemented the solution proposed by Ryan Bates in his Railscasts #73-75. Thus my Employee model has a virtual attribute skill_attributes; in the setter method skill_attributes=(), Skill.find_or_create_by_name() is called for each passed skill name. My code for this is not quite elegant, but it works just fine:
def skill_attributes=( skill_attributes ) self.skills.clear for attributes in skill_attributes unless attributes[ 'name' ].blank? skill = Skill.find_or_create_by_name( attributes[ 'name' ] ) self.skills << skill unless self.skills.include?( skill ) end end end
In the _form for the employees I just render the following partial for each skill:
<li class="skill"> <% fields_for "employee[skill_attributes]", skill do |skill_form| %> <%= skill_form.label :name, 'Skill: ' %><%= skill_form.text_field :name, :index => nil %> <%= link_to_function 'remove', "this.up( '.skill' ).remove()" %> <% end %> </li>
Using the "remove" link, the user can remove the skill entry (the <div> with the label and the text_field), new ones can be added by a link in the main form:
link_to_function 'Add skill' do |page| page.insert_html :bottom, :skills, :partial => 'skill', :object => Skill.new end
As mentioned above, this part is already working fine. However, I also want to add an auto completion feature using AJAX, because this was the motivation to use text fields in the first place (in a desktop application, I might have used a combo box for this). Using a slightly modified version of the auto_complete plugin, this is no problem in other parts of the application.
But in this case I am confronted with the problem that I (obviously) have to know the (html) id of each text field to create an Ajax.Autocompleter for it. But at the moment, the id shared by all text fields ("employee_skill_attributes__name"), and I have no idea about a "clean" way of assigning an unique one to the ones created by the client-side-only JavaScript link.
I can't get rid of this odd feeling that the solution is waiting right under my nose, but I am not enough of a JavaScript programmer to find a simple way to accomplish this...
Thanks in advance!