Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby on Rails field_for Form Helper Problems

I'm using the field_for form helper with a loop:

<% f.fields_for :permissions do |permission_form| %>
    <tr>
      <td><%= permission_form.object.security_module.name %><%= permission_form.hidden_field(:security_module_id) %></td>
      <td><%= permission_form.object.security_module.description %></td>
    <tr>
<% end %>

The resulting output of the above code is this:

    <input id="role_permissions_attributes_0_id" name="role[permissions_attributes][0][id]" type="hidden" value="76" />
    <tr>
      <td>Diary<input id="role_permissions_attributes_0_security_module_id" name="role[permissions_attributes][0][security_module_id]" type="hidden" value="13" /></td>
       <td>Access to the Diary Module</td>
    </tr>
    <!-- next input field then <tr> tag -->

The problem with this markup is that the input tag falls outside of the tr tag which there for causes validation issues with XHTML.

Does anyone know how I can have the input tag fall inside the tr tag therefore giving me valid XHTML 1.0 STRICT markup?

Thanks


2 Answers

If you take a look at the Rails source code you'll find this.

# in actionpack/lib/action_view/helpers/form_helper.rb
def fields_for_nested_model(name, object, args, block)
  if object.new_record?
    @template.fields_for(name, object, *args, &block)
  else
    @template.fields_for(name, object, *args) do |builder|
      @template.concat builder.hidden_field(:id)
      block.call(builder)
    end
  end
end

Notice it is adding the hidden field directly here, and it doesn't look like there is any option to change this behavior. The easiest thing is probably to create your own custom form builder.

# in lib/no_id_form_builder.rb
class NoIdFormBuilder < ActionView::Helpers::FormBuilder
  private
  def fields_for_nested_model(name, object, args, block)
    @template.fields_for(name, object, *args, &block)
  end
end

And then use this in your form. You'll need to add the id field manually.

<% f.fields_for :permissions, :builder => NoIdFormBuilder do |permission_form| %>
  <tr>
    <td>
      <%= permission_form.object.security_module.name %>
      <%= permission_form.hidden_field(:security_module_id) %>
      <%= permission_form.hidden_field(:id) unless permission_form.object.new_record? %>
    </td>
    <td><%= permission_form.object.security_module.description %></td>
  <tr>
<% end %>

You may want to submit a lighthouse ticket on this. perhaps there could be a :skip_id_field option to fields_for which does this.

like image 199
ryanb Avatar answered Feb 28 '26 15:02

ryanb


There is a workaround available as of 2.3.5. If you explicitly place the :id field, it won't implicitly add it for you:

<% form_for @foo do |f| %> 
<table> 
  <tbody> 
    <% f.fields_for :bars do |bf| %> 
      <tr>
        <td>
          <%= bf.hidden_field :id %>
          <%= bf.text_field :name %>
        </td> 
      </tr> 
    <% end %> 
  </tbody> 
</table> 
<% end %>

See https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/3259

like image 43
Tyler Rick Avatar answered Feb 28 '26 16:02

Tyler Rick