How to Use Nested Form in Rails: Syntax and Example
In Rails, use
accepts_nested_attributes_for in the parent model and fields_for in the form view to create nested forms. This allows you to edit attributes of associated child models within the same form.Syntax
To use nested forms in Rails, add accepts_nested_attributes_for :association_name in the parent model. In the form view, use fields_for :association_name inside the parent form to build fields for the child model.
In the controller, permit nested attributes in strong parameters with params.require(:parent).permit(..., association_attributes: [...]).
ruby
class Parent < ApplicationRecord
has_many :children
accepts_nested_attributes_for :children
end
# In the form view (ERB):
<%= form_with(model: @parent) do |form| %>
<%= form.text_field :name %>
<%= form.fields_for :children do |child_fields| %>
<%= child_fields.text_field :name %>
<% end %>
<%= form.submit %>
<% end %>Example
This example shows a Project model with many Tasks. The nested form lets you create or edit tasks inside the project form.
ruby
# app/models/project.rb class Project < ApplicationRecord has_many :tasks, inverse_of: :project accepts_nested_attributes_for :tasks, allow_destroy: true end # app/models/task.rb class Task < ApplicationRecord belongs_to :project end # app/controllers/projects_controller.rb class ProjectsController < ApplicationController def new @project = Project.new @project.tasks.build end def create @project = Project.new(project_params) if @project.save redirect_to @project else render :new end end private def project_params params.require(:project).permit(:name, tasks_attributes: [:id, :name, :_destroy]) end end # app/views/projects/new.html.erb <%= form_with(model: @project) do |form| %> <p> <%= form.label :name %><br> <%= form.text_field :name %> </p> <h3>Tasks</h3> <%= form.fields_for :tasks do |task_fields| %> <p> <%= task_fields.label :name %><br> <%= task_fields.text_field :name %> <%= task_fields.check_box :_destroy %> <%= task_fields.label :_destroy, "Remove task" %> </p> <% end %> <%= form.submit "Create Project" %> <% end %>
Output
A form page with fields for Project name and nested Task names, allowing creation of a project with multiple tasks in one form submission.
Common Pitfalls
- Forgetting to add
accepts_nested_attributes_forin the parent model causes nested fields to be ignored. - Not permitting nested attributes in strong parameters will block saving child records.
- Not building child objects in the controller (e.g.,
@parent.children.build) means no nested fields show on new forms. - Missing
inverse_ofon associations can cause validation issues.
ruby
# Wrong: Missing accepts_nested_attributes_for class Parent < ApplicationRecord has_many :children end # Right: class Parent < ApplicationRecord has_many :children, inverse_of: :parent accepts_nested_attributes_for :children end
Quick Reference
| Step | Description |
|---|---|
| Add association | Define has_many or has_one between models |
| Enable nested attributes | Use accepts_nested_attributes_for in parent model |
| Build child objects | Use build method in controller for new forms |
| Permit params | Allow nested attributes in strong parameters |
| Use fields_for | Nest child fields inside parent form view |
Key Takeaways
Use accepts_nested_attributes_for in the parent model to enable nested forms.
Use fields_for in the form view to create inputs for associated child models.
Permit nested attributes in the controller's strong parameters to allow saving.
Build child objects in the controller to show nested fields on new forms.
Add inverse_of on associations to avoid validation and saving issues.