Handle dynamic nested forms, same as Cocoon, but using StimulusJS
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
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
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>
<h3 class="text-xl mt-4">Tasks</h3>
<div class="my-2" data-controller="nested-rondo" data-nested-rondo-field-class-value="task-field">
<div data-nested-rondo-target="fieldContain">
<%= f.simple_fields_for :tasks do |task| %>
<%= render "task_fields", f: task %>
<% end %>
</div>
<div class="links">
<%= link_to_add_association "Add Task", f, :tasks %>
</div>
</div>
<div class="form-actions mt-4">
<%= f.button :submit %>
</div>
<% end %>
In your _task_fields
partial:
<div class="task-field">
<%= f.input :description %>
<%= f.input :done, as: :boolean %>
<%= link_to_remove_association "Remove Task", f %>
</div>
Using projects example, in your controller ProjectsController, your params method should look like:
def project_params
params.require(:project).permit(:name, :description, tasks_attributes: [:description, :done, :_destroy, :id])
end
params :_destroy
allow to delete tasks and :id
allow to update tasks on update action
Convention:
nested-rondo
. But you can change the name of Javascript file and the value of data-controller
to match your purpose.data-nested-rondo-target="fieldContain"
must be added to an element that wraps all nested fields, the new field will be appended to this element.data-nested-rondo-field-class-value
is used to detect the element that needs to be removed. Its value must match the class name of an element that wraps the partial. If you do not declare it, it will default remove the closest parent element.link_to_add_association
is named for the association name with the _fields
suffix. In this example, the partial is named task_fields
. You can change the partial name by passing the partial_name
option to link_to_add_association
.View details implement for this sample at rondo_form_demo_turbo_8
Bug reports and pull requests are welcome on GitHub at https://github.com/hungle00/rondo_form.
The gem is available as open source under the terms of the MIT License.