DEV Community

hungle00
hungle00

Posted on

5 1

Rails nested form (new gem with Stimulus)

Nested forms are forms that handle nested models and attributes in one form; e.g. a project with its tasks or an invoice with its line items.

Before Rails 6, Cocoon is a good choice for creating dynamic nested forms. But Cocoon needs jQuery to work well, it's a very old library on modern-day frontend frameworks.
When Stimulus is came out, Rails devs is suggested to use Stimulus as Javascript library in their projects. So, I created a gem for handling dynamic nested forms with Stimulus JS.

GitHub logo hungle00 / rondo_form

Same as Cocoon, but using StimulusJS https://rubygems.org/gems/rondo_form

RondoForm

Handle dynamic nested forms, same as Cocoon, but using StimulusJS

Installation

Install the gem and add to the application's Gemfile by executing:

$ bundle add rondo_form

Or inside the Gemfile add the following

$ gem 'rondo_form', '~> 0.2.6'

Run the installation task:

$ rails g rondo_form:install

Usage

For example, you have Project model, which has has_many relationship with Task model:

rails g scaffold Project name:string description:string
rails g model Task description:string done:boolean project:belongs_to

You need to add accepts_nested_attributes_for to Project model:

class Project < ApplicationRecord
  has_many :tasks, dependent: :destroy
  accepts_nested_attributes_for :tasks, reject_if: :all_blank, allow_destroy: true
end

Sample with SimpleForm

The RondoForm gem adds two helper functions: link_to_add_association and link_to_remove_association. The example below illustrates the way to use it.

In your projects/_form partial:

<%= simple_form_for(@project) do |f| %>
  <div class="form-inputs">
    <%= f.input :name %>
    <%= f.input :description %>
  </div
Enter fullscreen mode Exit fullscreen mode

Rondo Form is easy to use, it has the same tag helpers name as cocoon: link_to_add_association, link_to_remove_association.
This gem does not need JS dependencies to work with, when you run under command, it will generate nested_rondo_controller.js in your app/javascript/controllers/ folder:



rails g rondo_form:install 


Enter fullscreen mode Exit fullscreen mode

And auto import this controller into index.js.


 js
import NestedRondoController from "./nested_rondo_controller"
application.register("nested-rondo", NestedRondoController)


Enter fullscreen mode Exit fullscreen mode

You must add data-controller="nested-rondo" to an element, that wraps fields_for and link_to_add_association helper.
For example, we have Project model, which has has_many relationship with Task model.
In your projects/_form partial:


 erb
<%= simple_form_for(@project) do |f| %>
  <div class="form-inputs">
    <%= f.input :name %>
    <%= f.input :description %>
  </div>
  <h3>Tasks</h3>
  <div data-controller="nested-rondo">
    <%= f.simple_fields_for :tasks do |task| %>
      <%= render "task_fields", f: task %>
    <% end %>
    <div class="links">
      <%= link_to_add_association "Add Task", f, :tasks %>
    </div>
  </div>
  <%= f.button :submit %>
<% end %>


Enter fullscreen mode Exit fullscreen mode

In your _task_fields partial:


 erb
<div class="nested-fields">
  <%= f.input :description %>
  <%= f.input :done, as: :boolean %>
  <%= link_to_remove_association "Remove Task", f %>
</div>


Enter fullscreen mode Exit fullscreen mode

This sample I built with SimpleForm gem, but the idea is the same with Rails standard form.

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more

Top comments (1)

Collapse
 
marcelonmoraes profile image
Marcelo Moraes

Excelent.

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More