I have installed the cocoon gem in my rails 4 app exactly as described. This works fantastic in the parent model form allowing the user to add/remove fields for the child model(s). Where I'm having trouble is the submission of the child object. If child models are built in the parent model's new action, then I am able to submit exactly however many models were created, no more. This is obvious from the parameters being submitted as they contain child_attributes (or not, if no child models were built in the controller).
Currently running
rails 4.2.10
ruby 2.5.1
cocoon 1.2.14
jquery-rails 4.3.3
jquery-ui-rails 6.0.1
CODE SNIPPETS
class EventsController < ApplicationController
before_action :authenticate_user!, only: [:new, :create]
def new
@event = Event.new
@event.competitions.build
end
def create
@event = current_user.events.create(event_params)
if @event.valid?
flash[:notice] = "Event created"
redirect_to events_path
else
flash[:alert] = "Event not created. Please check for errors in the form and try again."
render :new, status: :unprocessable_entity
end
end
def event_params
params.require(:event).permit(
:event_name,
:event_start,
:event_end,
:event_address,
competitions_attributes: [:id, :competition_name, :maximum_participants, :type_id, :fee, :_destroy]
)
end
end
Parent model
acts_as_paranoid
has_and_belongs_to_many :users
has_many :competitions, dependent: :destroy, inverse_of: :event
belongs_to :address
accepts_nested_attributes_for :address
accepts_nested_attributes_for :competitions, allow_destroy: true
Child model
class Competition < ActiveRecord::Base
acts_as_paranoid
belongs_to :event
has_many :participants, dependent: :destroy
belongs_to :type
accepts_nested_attributes_for :participants, allow_destroy: true
Form (new.html.erb)
<div class="text-left ">
<%= simple_form_for @event do |f| %>
<%= f.input :event_name, input_html: {maxlength: 60} %>
<%= f.input :logo, label: "Event Logo:", hint: 'jpg or png files allowed, max size: 1MB' %>
<a <%= f.input :description, label_html: {class: "glyphicon glyphicon-question-sign event-new", href: "#", 'data-content': "You can format your description using the editor buttons. Cutting and pasting from other text editors will not work unless they are first exported into html format. For security reasons, some html tags are not allowed and will be removed.", rel: "popover", "data-placement": 'top', 'data-original-title': 'WYSIWYG editor help', 'data-trigger': 'hover' }, as: :ckeditor, input_html: { ckeditor: { toolbar: 'mini' } } %></a>
<%= f.input :event_address, placeholder: "Enter Street Address, City, State, Postal Code" %>
<%= f.input :registration_fee, :input_html => { :value => '0.00'}, label: "Team registration fee" %>
<%= f.input :event_start %>
<%= f.input :event_end %>
<br />
<h3>Competitions</h3>
<div id="competitions">
<%= f.simple_fields_for :competitions do |competition| %>
<%= render 'competition_fields', f: competition %>
<% end %>
<div class="links">
<%= link_to_add_association 'add competition', f, :competitions %>
</div>
</div>
<%= f.submit 'Create', :class => 'pull-right btn btn-primary' %>
<% end %>
</div
Partial (named _competition_fields.html.erb
<div class="nested-fields">
<%= f.input :competition_name %>
<%= f.collection_select(:type_id, @types, :id, :name, prompt: "Select a Type") %>
<%= f.input :fee, :input_html => { :value => '0.00'} %>
<%= f.input :maximum_participants %>
<%= link_to_remove_association "Delete Competition", f %>
</div>
application.js
//= require jquery
//= require bootstrap-sprockets
//= require jquery_ujs
//= require dataTables/jquery.dataTables
//= require jquery-ui/widgets/autocomplete
//= require autocomplete-rails
//= require moment
//= require bootstrap-datetimepicker
//= require ckeditor/init
//= require google_analytics
//= require cocoon
//= require_tree .
From the Rails console (after the parent model is inserted)
"competitions_attributes"=>{"0"=>{"competition_name"=>"test1", "type_id"=>"2", "fee"=>"0.00", "maximum_participants"=>"8", "_destroy"=>"false"}}}, "commit"=>"Create"}
SQL (17.4ms) INSERT INTO "competitions" ("competition_name", "maximum_participants", "type_id", "fee", "event_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id" [["competition_name", "test1"], ["maximum_participants", 8], ["type_id", 2], ["fee", "0.0"], ["event_id", 305], ["created_at", "2019-08-01 11:13:44.582299"], ["updated_at", "2019-08-01 11:13:44.582299"]]
I've been through all the usual issues with the setup for the gem (accepts_nested_attributes_for, inverse_of, the naming and indentation of the child_fields partial, jQuery is installed and cocoon being called etc.) It's all to spec so far as I can tell. And it works, as long as the child models are built in the new action.
Argh! What a facepalm moment. Turned out the <a>
tag on the ckeditor description field caused all this fuss. Removing the <a>
tag allowed cocoon to operate normally.
So, in answer to the original question: No, the cocoon gem does -not- require even one child model to be built in the new controller action to add them.