-
-
Save bkildow/0c1bd0db8d1e4acdbb1c to your computer and use it in GitHub Desktop.
| # app/forms/graduation_form.rb | |
| require 'concerns/nested_form' | |
| class GraduationForm < Reform::Form | |
| # Needed for correct behavior of virtual attributes, see https://github.com/apotonick/reform/issues/75 | |
| reform_2_0! | |
| model :response | |
| collection :minor_responses, populate_if_empty: MinorResponse do | |
| include Reform::NestedForm | |
| property :minor_name | |
| # only save this if minor_name isn't blank | |
| reject_if_blank :minor_name | |
| end | |
| end |
| # app/forms/concerns/nested_form.rb | |
| # Helps facilitates nested forms. loosely based on: https://github.com/apotonick/reform/issues/86#issuecomment-73918238 | |
| # Adds the ability to exclude saving if a particular field is blank, and helper methods to make cocoon gem work. | |
| module Reform | |
| module NestedForm | |
| extend ActiveSupport::Concern | |
| included do | |
| property :id, virtual: true | |
| property :_destroy, virtual: true | |
| @reject_field = [] | |
| end | |
| def sync_hash(options) | |
| if fields._destroy == '1' || reject_fields? | |
| model.mark_for_destruction | |
| end | |
| super(options) | |
| end | |
| def new_record? | |
| model.new_record? | |
| end | |
| def marked_for_destruction? | |
| model.marked_for_destruction? | |
| end | |
| def reject_fields? | |
| self.class.reject_field.any? { |f| fields[f].blank? } | |
| end | |
| class_methods do | |
| def reject_if_blank(field) | |
| @reject_field << field | |
| end | |
| def reject_field | |
| @reject_field | |
| end | |
| end | |
| end | |
| end |
| # app/models/response.rb | |
| class Response < ActiveRecord::Base | |
| # autosave: true is needed to get mark_for_destruction | |
| has_many :minor_responses, dependent: :destroy, autosave: true | |
| end |
@bkildow thanks for this just started refactoring an App that makes heavy use of cocoon to include reform - How Cocoon and reform would interact concerned me but evidently it is do able
@bkildow This worked for me with Trailblazer contracts, although I was getting undefined method 'build' for #<Disposable::Twin::Collection:...>
I found a workaround by overriding Cocoon::ViewHelpers#create_object_on_association. It expects the form collection to be ActiveRecord, with a build method, but Disposable::Twin::Collection doesn't have build. So I ask the model for the raw collection's buildinstead.
# via https://github.com/nathanvda/cocoon/blob/be59abd99027b0cce25dc4246c86d60b51c5e6f2/lib/cocoon/view_helpers.rb#L133-L136
module Cocoon
module ViewHelpers
def create_object_on_association(f, association, instance, force_non_association_create)
if instance.class.name == "Mongoid::Relations::Metadata" || force_non_association_create
create_object_with_conditions(instance)
else
assoc_obj = nil
if instance.collection?
if f.object.respond_to?(:model) && f.object.send(association).is_a?(Disposable::Twin::Collection)
# HACK! Add Disposable::Twin::Collection support
assoc_obj = f.object.model.send(association).build
f.object.model.send(association).delete(assoc_obj)
else
# assume ActiveRecord or compatible
assoc_obj = f.object.send(association).build
f.object.send(association).delete(assoc_obj)
end
else
assoc_obj = f.object.send("build_#{association}")
f.object.send(association).delete
end
assoc_obj = assoc_obj.dup if assoc_obj.frozen?
assoc_obj
end
end
end
endAlso, if you get undefined method 'reflect_on_association', be sure in your contract you include Reform::Form::ActiveModel::ModelReflections.
One more Trailblazer note: sync_hash is no longer part of the Reform API. So I commented out sync_hash and instead followed the instructions in the Trailblazer book re: "Removing Collection Items".
So the collection's skip_if looks like:
def skip_item?(fragment, options)
# don't process if it's getting destroyed!
if fragment["_destroy"] == "1"
items.delete(item.find { |x| x.id.to_s == fragment["id"] })
return true
end
endHere is an update that works with Reform 2.2.1:
https://gist.github.com/lucaspiller/615f09bb525a14163921fd56b4b8e611
In my use case, I want the field to show up, but not be required. When saving, I don't want to create the associated record if it is blank.