Dynamic Nested Forms in Ruby on Rails

This article will discuss how to create dynamic nested forms in Ruby on Rails using Cocoon gem. We will use two models, product and FAQ. The product can have multiple FAQs, which we will add manually while creating it.

gem "cocoon"
yarn add @nathanvda/cocoon

In app/javascripts/packs/application.js:

# app/javascripts/packs/application.js

require("@nathanvda/cocoon")

Let’s do some database stuff.

rails g scaffold Product name price:integer
rails g model Faq question answer product:belongs_to
rails db:migrate

In app/models/product.rb:

# app/models/product.rb

class Product < ApplicationRecord
 has_many :faqs, inverse_of: :product
 accepts_nested_attributes_for :faqs, reject_if: :all_blank, allow_destroy: true
end

In app/controllers/products_controller.rb:

# app/controllers/products_controller.rb

def product_params
 params.require(:product).permit(:name, :price, faqs_attributes: [:id, :question, :answer, :_destroy])
end

In app/views/products/_form.html.erb:

# app/views/products/_form.html.erb

<%= semantic_form_for @product do |f| %>
 <% f.inputs do %>
   <%= f.input :name %>
   <%= f.input :price %>
   <h3>FAQs</h3>
   <div id='faqs'>
     <%= f.semantic_fields_for :faqs do |faq| %>
       <%= render 'faq_fields', :f => faq %>
     <% end %>
     <div class='links'>
       <%= link_to_add_association 'add faq', f, :faqs %>
     </div>
   </div>
   <% f.buttons do %>
     <%= f.submit 'Save' %>
   <% end %>
 <% end %>
<% end %>

Create a new partial app/views/products/_faq_fields.html.erb:

# app/views/products/_faq_fields.html.erb

<div class='nested-fields'>
 <%= f.inputs do %>
   <%= f.input :question %>
   <%= f.input :answer %>
   <%= link_to_remove_association "remove faq", f %>
 <% end %>
</div>

You’ll also need to make certain that Jquery is properly added to your project. Happy nesting!