Rails - how to send a form that is inside another form?

user984621 picture user984621 · Aug 2, 2014 · Viewed 14.3k times · Source

I have this structure in my view:

<%= simple_form_for @user ... %>
  ...
  ...
  <%= render '/hobbies/form', :user => @user %>
  ...
  ...
<% end %>

The render part loads data from a partial - there's a form. The form-fields are successfully loaded (like inputs, submit input, radio buttons etc), but when I take a look at the generated HTML, in the rendered form is missing <%= form_for... and the closing tag.

Which means when I click to the submit button from the rendered form, this rendered form is not sent out, but instead of it is sent out the "big" for - simple_form_for.

How to make the rendered form sendable?

Thank you

Answer

Richard Peck picture Richard Peck · Aug 3, 2014

Simply, you can't have two separate nested forms.

You can have nested associated forms using accepts_nested_attributes_for - this is dependent on the structure of your models in the backend, which I'll detail below.

--

Forms

The most important thing you need to know is that Rails just builds HTML forms - which means they have to abide by all the constraints & rules these forms stipulate:

enter image description here

Each form has its own action attribute - which is how your browser knows where to send the data. If you have multiple / nested forms, you'll basically have two of these "action" attributes; preventing HTML from sending the form correctly

--

Nested

If you want to use some Rails conventions, you'll be better using the accepts_nested_attributes_for method. This resides in the model, and in order to use it effectively, you need to ensure you have your ActiveRecord associations set up correctly:

#app/models/user.rb
Class User < ActiveRecord::Base
   has_many :hobbies
   accepts_nested_attributes_for :hobbies
end

#app/models/hobby.rb
Class Hobbies < ActiveRecord::Base
   belongs_to :user
end

The importance of the association is crucial - Rails will pass "nested" model data through to each other. The nested model data is only there if the models are associated correctly with ActiveRecord (as above)

You can then pass the data through your controller / models as follows:

#app/controllers/users_controller.rb
Class UsersController < ApplicationController
   def new
       @user = User.new
       @user.hobbies.build # -> essential for nested attributes 
   end

   def create
      @user = User.new(user_params)
      @user.save #-> notice how this saves the @user model only?
   end

   private

   def user_params
      params.require(:user).permit(:user, :attributes, hobbies_attributes: [:hobbies, :attributes])
   end
end

This will allow you to include the hobbies part of the form as follows:

<%= form_for @user do |f| %>
   <%= f.fields_for :hobbies do |h| %>
       <%= h.text_field :your_attributes %>
   <% end %>
<% end %>