-
-
Save lucaspiller/615f09bb525a14163921fd56b4b8e611 to your computer and use it in GitHub Desktop.
= f.simple_fields_for :inputs do |input| | |
= render 'input_fields', f: input | |
.links | |
= link_to_add_association f, :inputs, partial: 'input_fields', force_non_association_create: true do | |
Add |
.nested-fields | |
= f.input :foo, as: :string | |
= f.input :bar, as: :string | |
= f.hidden_field :_destroy | |
= f.hidden_field :id | |
= link_to_remove_association f do | |
Delete |
class IndicatorForm < Reform::Form | |
InputPrepopulator = -> (options) { | |
if inputs.size == 0 | |
inputs << IndicatorInput.new | |
end | |
} | |
InputPopulator = -> (options) { | |
fragment, collection, index = options[:fragment], options[:model], options[:index] | |
if fragment["_destroy"] == "1" | |
# Marked for removal | |
collection.delete_at(index) | |
return skip! | |
else | |
(item = collection[index]) ? item : collection.insert(index, IndicatorInput.new). | |
end | |
} | |
collection :inputs, inherit: true, prepopulator: InputPrepopulator, populator: InputPopulator do | |
include NestedForm | |
property :foo | |
property :bar | |
end | |
end |
module NestedForm | |
extend ActiveSupport::Concern | |
included do | |
property :id, writeable: false | |
property :_destroy, virtual: true | |
end | |
def new_record? | |
model.new_record? | |
end | |
def marked_for_destruction? | |
model.marked_for_destruction? | |
end | |
end |
I found problems with both. The last populator was overwriting the other new records when adding more than one new record at a time.
This works for me.
InputPopulator = -> (options) {
fragment, collection, index = options[:fragment], options[:model], options[:index]
if fragment[:id].to_s == ""
item=nil
else
item = collection.find { |item| item.id.to_s == fragment[:id].to_s }
end
if fragment["_destroy"] == "1"
# Marked for removal
collection.delete(item) if item
return skip!
else
item ? item : collection.append(IndicatorInput.new)
end
}
Hey! Have you experienced any issues with required fields the asterisk not showing on the simple_fields_for
fields? It seem that cocoon is reflecting on the Models association and therefore building an object that has no validations on it as the validations are in Reform.
I found the above very useful.
It may help others to share an issue I came across (using Cocoon and Rails with fields_for) if you have more than one level of nesting. That is, if within the _input_fields partial you want another link_to_add_association for a further has_many association.
The problem (here: https://github.com/nathanvda/cocoon/blob/master/lib/cocoon/view_helpers.rb#L95) is that cocoon bases the nested fields for an associated object on a pure instance of the model, rather than that model wrapped in the Reform form object. (Not a criticism, just the way it's designed.) That's fine until you want to render fields for an association on that nested object, because the setup for the nested attributes is defined in your Reform form object, not your model. Essentially f.object
in _input_fields
is the actual model, not the form object. Unless the model itself has accept_nested_attributes configured, fields_for
won't treat the attribute as a nested_attributes_association
and the html markup won't name the fields in such a way that reform-rails can parse them into properly nested parameters.
The solution for me was using wrap_object
to ensure the record cocoon uses is the model wrapped in the relevant form object, like this:
<%= link_to_add_association 'Add Supporting Image', f, :images, partial: 'web_app/report/supporting_image_fields', force_non_association_create: true, wrap_object: Proc.new {|image| Report::WebAppCreation::ImageWithoutHotspotsForm.new(image) } %>
(There's probably a better way to get the form but this gives the idea).
This is really helpful, link_to_add_association
raises undefined method
reflect_on_association' for NilClass:Class`
in order to solve it
class IndicatorForm < Reform::Form
...
def self.reflect_on_association(obj)
Indicator.reflect_on_association(obj)
end
end
I found that
InputPopulator
does not work on removing some items.I've fixed this problem.