Rails: Getting the id of form fields inside a fields_for block

Something that seems to crop up a lot when working with nested forms is the need to access the id of an input field generated inside a fields_for loop. The problem is that the FormBuilder object doesn't expose its index attribute, so you can't specify the full id of the field. For example:

<% person_form,fields_for :attributes do |attributes_form| -%>

  # This text field's id will be in the format person_attributes_[index]_name

  <%= f.text_field :name %>

   # No way to know what [index] should be

  <%= observe_field :person_attributes_[index]_name, ... %>

<% end -%>```



I hit this problem a few days ago when I wanted to setup autocompleters on a dynamically generated field. I ended up posting a solution to [Google Groups](http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/fbaffb284d7e504c/d1e2047bd214ed1b#d1e2047bd214ed1b). For completeness, I'm reposting the code with all my typos removed.


### Where does the index come from?


To find out how the FormBuilder generates its field ids, I delved into the Rails source code and found a couple of helper methods in the `InstanceTagMethods` module ([source](http://github.com/rails/rails/blob/master/)).


The methods of interest are `sanitized_object_name` and `sanitized_method_name`. They take the name of the FormBuilder's model object (which is publicly accessible) and return the generated form element id (e.g. `person[attributes][0][name]` becomes `person_attributes_0_name`).


However, the methods that work this magic are private to the `InstanceTagMethods` module, so you can't get at them from within your `fields_for` block.


### Exposing the generated form field ids


I decided to duplicate these methods in my `application_helper.rb`, making them available to my fields_for block. Whilst not DRY, this is so far the only solution I've found for exposing the FormBuilder's index:

ruby# app/helpers/application_helper.rb

def sanitizedobjectname(object_name)

objectname.gsub(/][|[^-a-zA-Z0-9:.]/,"").sub(/_$/,"")

end

def sanitizedmethodname(method_name)

method_name.sub(/?$/, "")

end

def formtagid(objectname, methodname)

"#{sanitizedobjectname(objectname.tos)}#{sanitizedmethodname(methodname.to_s)}"

end```

```ruby# app/views/people/personattributes.rb

wrapped in personform,fieldsfor :attributes do |attributes_form|

<%= f.text_field :name %>

<%= observefield formtagid(f.objectname, :name), ... %>```

This code works for indexed partials (i.e. those with indexes based on their model id), and those generated with timestamp indexes such as in Ryan Bates' latest nested form code for Rails 2.3 -

http://github.com/ryanb/complex-form-examples.