Skip to content

Instantly share code, notes, and snippets.

@fran-worley

fran-worley/_form.html.erb

Last active Oct 23, 2017
Embed
What would you like to do?
A working example of nested forms just using Reform.
#views/users/_form.html.erb
<%= simple_form_for @form do |f| %>
<%= f.error_notification %>
<%= f.input :name %>
<%= f.input :email %>
<h4>
<%= link_to_add_fields icon(:plus),
f,
:assignments,
class: "btn btn-success",
append_selector: "#user_assignments tbody tr:first",
new_object: AssignmentForm.new(Assignment.new) %>
Assignments
</h4>
<table class="table table-hover table-bordered" id="user_assignments">
<thead>
<tr>
<th>Assignment</th>
<th></th>
</tr>
</thead>
<tbody>
<%= f.simple_fields_for :assignments do |builder| %>
<tr>
<td>
<%= f.input :assignment_id,
label: false,
collection: @assignments,
prompt: "Select a assignment" %>
</td>
<td>
<%= f.hidden_field :_destroy, class: "destroy-input" %><!--Set via javascript on click of remove button -->
<%= link_to "Remove", '#', class: "remove_fields btn btn-xs btn-danger" %></td>
</td>
</tr>
<% end %>
</tbody>
</table>
<%= f.button :submit %> <%= link_to "Cancel", :back, class: 'btn btn-warning' %>
<% end %>
#models/assignment.rb
class Assignment < ActiveRecord::Base
belongs_to :user
end #class Assignment
#forms/assignment_form.rb
class AssignmentForm < Reform::Form
property :id, type: Integer, writeable: false
property :_destroy, virtual: true
property :assignment_id, type: Integer
validation :default do
key(:assignments_id) { |assignment_id| assignment_id.filled? & assignment_id.int? }
end
end #class AssignmentForm
#forms/reform/nested_form.rb
module Reform
module NestedForm
extend ActiveSupport::Concern #might not be needed... Infact probably isn't
def nested_removeable!(collection:, fragment:, binding:, **)
deserialized_item = collection.find { |item| item.id.to_s == fragment["id"] } if fragment["id"].present?
if fragment["_destroy"] == "true" # don't process if it's getting removed!
collection.delete(deserialized_item) if deserialized_item.present?
return skip!
else
return deserialized_item || collection.append(model.send(binding.name).new)
end
end
end
end
#assets/javascripts/nested_forms.js.coffee
#add fields to form. used by nested forms
$.fn.addFields = (id, fields) ->
time = new Date().getTime()
id = new RegExp(id, "g")
fields = $(fields.replace(id, time))
this.before(fields)
#remove fields from form. used by nested forms
$.fn.removeFields = (destroyInputSelector = ".destroy-input") ->
this.find(destroyInputSelector).val('true')
this.hide()
this
jQuery ->
#enables add and remove fields from nested forms
$('form').on 'click', '.remove_fields', (event) ->
$($(this).attr("data-fields-selector")).removeFields()
event.preventDefault()
$('form').on 'click', '.add_fields', (event) ->
$($(this).data("append-selector")).addFields($(this).data('id'), $(this).data('fields'))
event.preventDefault()
#models/user.rb
class User < ActiveRecord::Base
has_many :assignments
end #class User
#forms/user_form.rb
class UserForm < Reform::Form
include Reform::NestedForm
property :name
property :email
collection :assignments, populator: :nested_removeable!, skip_if: :all_blank, form: AssignmentForm
def prepopulate!(options={})
return if model.client.blank?
self.assignments << model.assignments.new if assignments.size == 0
end
end #class UserForm
@Mbuckley0

This comment has been minimized.

Copy link

@Mbuckley0 Mbuckley0 commented Nov 29, 2016

You are using a link_to_add_fields helper method in your view but this is not defined anywhere in this gist. Where does this come from?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.