When using the form_for
helper and a text_field
call, Ruby on Rails will generate a unique id for the element that it outp
Look at the form builder options:
<%= form_for @user do |f| %>
<% form_css_id = "#" + f.options[:html][:id] %>
<% end %>
Options should at least include the following data: css class, id, http method and authenticity token.
I don't really like my own solution that much, but I tried not to go and patch InstanceTag.
Unfortunately that meant lifting the sanitization code from ActionView::Helpers::InstanceTagMethods
class MyCoolFormBuilder < ActionView::Helpers::FormBuilder
def sanitized_object_name
@sanitized_object_name ||= object_name.gsub(/\]\[|[^-a-zA-Z0-9:.]/, "_").sub(/_$/, "")
end
def field_id_for(method)
"#{sanitized_object_name}_#{method.to_s.sub(/\?$/,"")}"
end
end
In case someone has a FormBuilder object from a fields_for
block, it is possible to get its id
using this snippet:
<%= form.fields_for :something do |fields_form| %>
<%= fields_form.object_name.gsub(/[\[\]]+/, '_').chop %>id
<% end %>
FieldsForm#object_name
returns the field's ID as something like this: user[address][0]
. Next, the regex substitution changes groups of one or more brackets to underscores. This substitution leaves a trailing underscore, to which it appends the letters id
. For the example provided before, this results in user_address_0_id
.
In Rails 4.1 I was able to get the id with this:
ActionView::Base::Tags::Base.new(
f.object_name,
:username,
:this_param_is_ignored,
).send(:tag_id)
It works with nested forms (fields_for
).
I assume that there are multiple form_for
in the page and each has it's own submit button. I think this is how I would do this:
Have a hidden field in the the form_for and set it's value to the id of the input field. Here I've chosen input_#{n}
as the id of the input field. Of course I'll define the id for each input.
<%= form_for @user do |f| %>
<%= f.text_field :username, id: "input_#{n}" %>
<%= hidden_field_tag 'user[input_id]', value: "input_#{n}" %>
<%= f.submit %>
<% end %>
Then on submit I can get the id the form input in my params params[:user][:input_id]
which I can pass to the js.erb
using the locals
.
Hope this helps :)
I ended up creating a custom form builder to expose the property directly
class FormBuilder < ActionView::Helpers::FormBuilder
def id_for(method, options={})
InstanceTag.new( object_name, method, self, object ) \
.id_for( options )
end
end
class InstanceTag < ActionView::Helpers::InstanceTag
def id_for( options )
add_default_name_and_id(options)
options['id']
end
end
Then set the default form builder
ActionView::Base.default_form_builder = FormBuilder