Search code examples
ruby-on-railscocoon-gem

Rails: Nested fields inside a nested form


I have the following three models and associations:

class ParentProduct < ApplicationRecord
  has_many :child_products
  accepts_nested_attributes_for :child_products, allow_destroy: true
  has_many :attachments, dependent: :destroy
  accepts_nested_attributes_for :attachments, allow_destroy: true
end

class ChildProduct < ApplicationRecord
  belongs_to :parent_product
  has_many :attachments, dependent: :destroy
  accepts_nested_attributes_for :attachments, allow_destroy: true
end

class Attachment < ApplicationRecord
  belongs_to :parent_product, optional: true
  belongs_to :child_product, optional: true
  mount_uploader :image, AttachmentUploader
end

The purpose of this setup is to create a parent product with its attachments. And if the user want's, he can create a child product along with its attachments and associate it to that parent product.

In the new parent_products_controller I have the following setup in order to initially add 8 attachment fields. Also I don't want to initially show the child_product_fields, that's why I haven't added this @parent_product.child_products.build:

def new
  @parent_product = ParentProduct.new
  8.times{ @parent_product.attachments.build }
end

Inside the form that I'm creating the parent product, I have the attachments nested fields in order to create the attachments for the parent product. And when the user clicks on the add a product variation link it opens up the child_product_fields:

<%= simple_form_for @parent_product, url: parent_product_path, method: :post, validate: true do |f| %>

  <%= f.simple_fields_for :attachments do |attachment| %>
    <%= render 'parent_products/attachment_fields', form: attachment  %>
  <% end %>

  <%= f.simple_fields_for :child_products do |child_product| %>
    <%= render 'parent_products/child_product_fields', form: child_product %>
  <% end %>

  <div class="links float-right" style="margin-bottom: 30px;">
     <%= link_to_add_association raw('<i class="far fa-plus-square"></i> Add a product variation'), f, :child_products, form_name: 'form', :style=>"color: grey; font-size: 14px;" %>
   </div>
<% end %>

Now inside the child_product_fields I have one more attachment nested fields in order to create the attachments for the child product.

<%= form.simple_fields_for :attachments do |attachment| %>
  <%= render 'parent_products/attachment_fields', form: attachment  %>
<% end %>

The issue now is that I cant get the 8 attachment fields to show when I click and open the child_product_fields. The setup I'm after is.... when I click and open the child_product_fields, the 8 attachment fields should also appear. Any idea on how I can implement this?


Solution

  • You can use the :wrap_object option of link_to_add_association. It allows to add extra initialisation before rendering the nested form. So in your case, you could add 8 attachments to a child-product.

    E.g. do something like

    <div class="links float-right" style="margin-bottom: 30px;">
      <%= link_to_add_association raw('<i class="far fa-plus-square"></i> Add a product variation'), 
            f, :child_products, form_name: 'form',
            wrap_object: Proc.new {|child| 8.times {child.attachments.build }; child }, 
            style: "color: grey; font-size: 14px;" %>
    </div>