Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/stevepolitodesign/rails-nested-form-example
Create a nested form from scratch in Ruby on Rails 6
https://github.com/stevepolitodesign/rails-nested-form-example
Last synced: about 17 hours ago
JSON representation
Create a nested form from scratch in Ruby on Rails 6
- Host: GitHub
- URL: https://github.com/stevepolitodesign/rails-nested-form-example
- Owner: stevepolitodesign
- Created: 2019-11-06T13:10:02.000Z (almost 5 years ago)
- Default Branch: master
- Last Pushed: 2023-01-19T15:43:32.000Z (over 1 year ago)
- Last Synced: 2023-03-06T00:21:58.945Z (over 1 year ago)
- Language: Ruby
- Homepage: https://stevepolito.design/blog/create-a-nested-form-in-rails-from-scratch/
- Size: 1.07 MB
- Stars: 12
- Watchers: 1
- Forks: 3
- Open Issues: 36
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Rails Nested Form Example
A guide to adding [fields on the fly](https://guides.rubyonrails.org/form_helpers.html#adding-fields-on-the-fly) in a [nested form](https://guides.rubyonrails.org/form_helpers.html#building-complex-forms) using Rails 6.
Inspired by [cocoon](https://github.com/nathanvda/cocoon) and [Ryan Bates](http://railscasts.com/episodes/196-nested-model-form-revised).
## 1. Configuring the Model
```ruby
class Person < ApplicationRecord
has_many :addresses, inverse_of: :person
accepts_nested_attributes_for :addresses, allow_destroy: true, reject_if: :all_blank
end
```## 2. Declare the Permitted Parameters
```ruby
class PeopleController < ApplicationController
...
privatedef person_params
params.require(:person).permit(:first_name, :last_name, addresses_attributes: [:id, :kind, :street, :_destroy])
end
end
```## 3. Create a Form Partial
```erb
<%# app/views/people/_address_fields.html.erb %>
<%= f.hidden_field :_destroy %>
<%= f.label :kind %>
<%= f.text_field :kind %>
<%= f.label :street %>
<%= f.text_field :street %>
<%= link_to "Remove", '#', class: "remove_fields" %>
``````erb
<%# app/views/people/_form.html.erb %>
<%= form_with model: @person, local: true do |f| %>
...
Addresses:
<%= f.fields_for :addresses do |addresses_form| %>
<%= render "address_fields", f: addresses_form %>
<% end %>
<%= link_to_add_fields "Add Addresses", f, :addresses %>
<%= f.submit %>
<% end %>
```## 4. Create a Helper Function
```ruby
# app/helpers/application_helper.rb
module ApplicationHelper
def link_to_add_fields(name, f, association)
new_object = f.object.send(association).klass.new
id = new_object.object_id
fields = f.fields_for(association, new_object, child_index: id) do |builder|
render(association.to_s.singularize + "_fields", f: builder)
end
link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end
end
```## 5. Add Javascript
```javascript
// app/javascript/packs/nested-forms/addFields.js
class addFields {
constructor() {
this.links = document.querySelectorAll(".add_fields");
this.iterateLinks();
}iterateLinks() {
if (this.links.length === 0) return;
this.links.forEach((link) => {
link.addEventListener("click", (e) => {
this.handleClick(link, e);
});
});
}handleClick(link, e) {
if (!link || !e) return;
e.preventDefault();
let time = new Date().getTime();
let linkId = link.dataset.id;
let regexp = linkId ? new RegExp(linkId, "g") : null;
let newFields = regexp ? link.dataset.fields.replace(regexp, time) : null;
newFields ? link.insertAdjacentHTML("beforebegin", newFields) : null;
}
}window.addEventListener("turbolinks:load", () => new addFields());
``````javascript
// app/javascript/packs/nested-forms/removeFields.js
class removeFields {
constructor() {
this.iterateLinks();
}iterateLinks() {
document.addEventListener("click", (e) => {
if (e.target && e.target.className == "remove_fields") {
this.handleClick(e.target, e);
}
});
}handleClick(link, e) {
if (!link || !e) return;
e.preventDefault();
let fieldParent = link.closest(".nested-fields");
let deleteField = fieldParent
? fieldParent.querySelector('input[type="hidden"]')
: null;
if (deleteField) {
deleteField.value = 1;
fieldParent.style.display = "none";
}
}
}window.addEventListener("turbolinks:load", () => new removeFields());
``````javascript
// app/javascript/packs/application.js
require("./nested-forms/addFields");
require("./nested-forms/removeFields");
```