# Terminal
gem install rails --pre
rails g scaffold todo_list name
rails g model task todo_list:belongs_to description
yarn add stimulus
# models/todo_list.rb
class TodoList < ApplicationRecord
has_many :tasks, dependent: :destroy
accepts_nested_attributes_for :tasks, allow_destroy: true, reject_if: proc { |attr| attr['description'].blank? }
end
# models/task.rb
class Task < ApplicationRecord
belongs_to :todo_list
end
# todo_lists_controller.rb
def todo_list_params
params.require(:todo_list).permit(:name, tasks_attributes: [:_destroy, :id, :description])
end
# app/javascript/packs/application.js
import { Application } from "stimulus"
import { definitionsFromContext } from "stimulus/webpack-helpers"
const application = Application.start()
const context = require.context("../controllers", true, /\.js$/)
application.load(definitionsFromContext(context))
# app/javascript/controllers/nested_form_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["add_item", "template"]
add_association(event) {
event.preventDefault()
var content = this.templateTarget.innerHTML.replace(/TEMPLATE_RECORD/g, new Date().valueOf())
this.add_itemTarget.insertAdjacentHTML('beforebegin', content)
}
remove_association(event) {
event.preventDefault()
let item = event.target.closest(".nested-fields")
item.querySelector("input[name*='_destroy']").value = 1
item.style.display = 'none'
}
}
# todo_lists/_form.html.erb
<h1>Tasks</h1>
<div data-controller="nested-form">
<template data-target='nested-form.template'>
<%= form.fields_for :tasks, Task.new, child_index: 'TEMPLATE_RECORD' do |task| %>
<%= render 'task_fields', form: task %>
<% end %>
</template>
<%= form.fields_for :tasks do |task| %>
<%= render 'task_fields', form: task %>
<% end %>
<div data-target="nested-form.add_item">
<%= link_to "Add Task", "#", data: { action: "nested-form#add_association" } %>
</div>
</div>
# _task_fields.html.erb
<div class='nested-fields'>
<div class='form-group'>
<%= form.hidden_field :_destroy %>
<%= form.text_field :description, placeholder: 'Description', class: 'form-control' %>
<small>
<%= link_to "Remove", "#", data: { action: "click->nested-form#remove_association" } %>
</small>
</div>
</div>