Add dynamically generated forms to your model’s form for any of its associations. For example if you have a Job model that has_many Task then this gem will assist you in adding all the JavaScript necessary to allow your users to click an “Add Task” button on your edit view, the view will then append a new form to the DOM with all the field attributes formatted for rails (id, name, etc) plus will add any necessary hidden fields for existing records (task.id).
There is also JS events raised when an entry is added or removed so you can hook up your code for pre-form submission editing.
Any entries added or removed won’t update the DB until the form is submitted.
Installation
Add this line to your application’s Gemfile:
$ gem 'cool_nested_forms'
And then execute:
$ bundle install
Or install it yourself as:
$ gem install cool_nested_forms
Then require the JavaScript in your app/assets/javascripts/application.js
//= require cool_nested_forms
Usage Example
For this example I will use Job and Task models
Preparing your models
Job Model
class Job < ApplicationRecord has_many :tasks, :dependent => :destroy # we need to accepts_nested_attributes_for Task # :name is required in this example - Use your own required field here or remove the reject_if call # :allow_destroy => true so we can delete entries when passing the _destroy field accepts_nested_attributes_for :tasks, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true end
Task Model
class Task < ApplicationRecord belongs_to :job end
Preparing the Job Controller
class JobsController < ApplicationController # include the CoolNestedFormsHelper helper CoolNestedFormsHelper # other code def job_params # :id and :_destroy are required. Substitute name with your own fields params.require(:job).permit(:name, :tasks_attributes => [:id, :name, :_destroy]) end end
The partials used to generate the new and existing tasks
We need to provide cool_nested_forms two partials. One for new and one
for existing records. They will be placed under the Job's view folder. Make sure the
id field of the container is set like so: id="<%= id %>"
app/views/jobs/_task_new.html.rb
<%= builder.hidden_field :_destroy, :class => 'cnf-removable' %> <%= builder.label :name %> <%= builder.text_field :name %> <%= remove_entry_button "Remove", Task, {:target => id} %>
app/views/jobs/_task_edit.html.rb
<%= builder.hidden_field :_destroy, :class => 'cnf-removable' %> <%= builder.hidden_field :id %> <%= builder.label :name %> <%= builder.text_field :name %> <%= remove_entry_button "Remove", Task, {:target => id} %>
Adding functionality to the Job form
app/views/jobs/_form.html.erb
<%= form_with(model: job, local: true) do |form| %> <%= new_entry_template(form,Task) %> <%= new_entry_button("Add Task", Task )%> <%= entries_container(form,Task,job.tasks) %> <% end %>;
After add/remove events
If you need to perform any other javascript actions after an entry is added or
removed, you can add a listener to these events
coolNestedForms.entryAdded
coolNestedForms.entryRemoved
Something like this
$(document).bind('coolNestedForms.childAdded', function(){ // do something });
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/CarlosRoque/cool_nested_forms. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
License
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).