0
0
RailsHow-ToBeginner · 4 min read

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_for in 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_of on 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

StepDescription
Add associationDefine has_many or has_one between models
Enable nested attributesUse accepts_nested_attributes_for in parent model
Build child objectsUse build method in controller for new forms
Permit paramsAllow nested attributes in strong parameters
Use fields_forNest 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.