I have a form with 4 nested levels that I'm using to dynamically add items, shipments, and calculate costs. I have the form set up to where I can add/remove everything I need with button clicks. Everything about the initial render of the page is as expected.
However, when I go to add new instances of the mid-level nests (the SubQuote and QuoteShipment), it only renders itself (e.g. SubQuote) and not any of the partials referenced in its partial (QuoteShipment). I want a button click to render all of the nested partials beneath of it automatically.
My relevant models are structured:
class Quote < ApplicationRecord
has_many :sub_quotes, dependent: :destroy, inverse_of: :quote
accepts_nested_attributes_for :sub_quotes, reject_if: :all_blank
end
class SubQuote < ApplicationRecord
belongs_to :quote
has_many :quote_shipments, dependent: :destroy, inverse_of: :sub_quote
accepts_nested_attributes_for :quote_shipments, reject_if: :all_blank
end
class QuoteShipment < ApplicationRecord
has_many :quote_items, dependent: :destroy, inverse_of: :quote_shipment, class_name: "::QuoteItem"
belongs_to :sub_quote
accepts_nested_attributes_for :quote_items, reject_if: :all_blank
end
Class QuoteItem < ApplicationRecord
belongs_to :quote_shipment
end
Partial for SubQuote class that renders the QuoteShipment partial on page load, but not on link_to_add_association click.
<div class="col nested-sub_quote-fields" id="sub_quote_identifier">
<div class="row">
<%= link_to_remove_association button_tag('remove sub_quote', type: "button", class: "btn btn-sm btn-outline red-btn add-quote"), f , { wrapper_class: "nested-sub_quote-fields" }%>
</div>
<div class="row" class="">
<div id="sub_quote" class="col mt-0 mt-md-4 mb-4 p-0">
<div class="col ">
<div class="col-lg col-sm-12 col-md-12">
<%= f.fields_for :quote_shipments do |shipment| %>
<%= render partial: "quotes/quote_shipment_fields", :locals => { :f => shipment } %>
<% end %>
<div class='links'>
<%= link_to_add_association button_tag('Add Shipment', type: "button", class: "btn btn-sm btn-outline btn-primary add-quote"), f, :quote_shipments %>
</div>
</div>
</div>
</div>
<div class="col-lg-5 col-sm-12 col-md-12">
<%= render partial: "quotes/cost", locals: { f: f } %>
</div>
</div>
</div>
For example with the above relationships:
If I clicked the link_to_add_association for the SubQuote class, I would like for it to render the SubQuote partial, as well as 1 instance of the QuoteShipment partial, and 1 instance of the QuoteItem partial.
If I clicked the link_to_add_association for the QuoteShipment partial, I'd like it to render with 1 instance of the QuoteItem partial nested beneath the new QuoteShipment partial.
I've tried:
I think in a worse case scenario, I could generate different partials for each different level's link_to_add_association button that I have, but that seems very redundant
The link_to_add_association
has the :wrap_object
option (check documentation) that allows to add extra initialisation before rendering the partial.
So in your case you could so something like:
= link_to_add_association button_tag('Add Shipment', type: "button", class: "btn btn-sm btn-outline btn-primary add-quote"),
f, :quote_shipments,
wrap_object: Proc.new{|shipment| shipment.quote_items.build; shipment }
Inside the wrap_object
partial you could do any initialisation you want, as long as you return the to be rendered nested item (in this example shipment
).
And in this example we build
a QuoteItem
so it will be rendered.
For the SubQuote
you could so something similar. E.g. something like
wrap_object: Proc.new{|sub_quote| shipment = sub_quote.quote_shipments.build; shipment.quote_items.build; sub_quote }