问题
I have a genearted lineItem field using Cocoon gem, am having issues trying to save the line items field values,and when I inspect the elements the add_item button wasn't triggering a unique ID for each new field generated.
class InvoicesController < ApplicationController
before_action :set_invoice,:set_line_item, only: [:show, :edit, :update, :destroy]
def index
@invoices = Invoice.all
end
def show
end
def new
@invoice = Invoice.new
@invoice.line_items.build
end
def edit
end
def create
@invoice = Invoice.new(invoice_params)
respond_to do |format|
if @invoice.save
format.html { redirect_to @invoice, notice: 'Invoice was successfully created.' }
format.json { render :show, status: :created, location: @invoice }
else
format.html { render :new }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if @invoice.update(invoice_params)
format.html { redirect_to @invoice, notice: 'Invoice was
successfully updated.' }
format.json { render :show, status: :ok, location: @invoice }
else
format.html { render :edit }
format.json { render json: @invoice.errors, status: :unprocessable_entity }
end
end
end
def destroy
@invoice.destroy
respond_to do |format|
format.html { redirect_to invoices_url, notice: 'Invoice was successfully destroyed.' }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_invoice
@invoice = Invoice.find(params[:id])
end
def set_line_item
@line_item = LineItem.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
#def invoice_params
#params.require(:invoice).permit(:total_amount, :issue_date, :currency, :description)
#end
def invoice_params
params.require(:invoice).permit(:amount, :date, :currency, {line_items_attributes: [:id,:quantity,:net_amount, :description, :unit_cost]})
end
end
This is my form partial view enter image description here
<div class="container">
<div class="row">
<div class="col">
<%= f.label :date %>
<%= f.input_field :date , class: "form-control datepicker", as: :string, id: "invoice_date" %>
</div>
<div class="col">
<%= f.label :currency %>
<%= f.input_field :currency , class: "form-control" , id: "invoice_currency" %>
</div>
<div class="col">
<h5>Amount Due : <span class="bal" id="invoice_total">679.00</span><span class="subtotal_currency">
</span></h5>
</div>
</div>
</div>
</div>
<table class="table">
<thead>
<tr>
<th class="description">Description</th>
<th class="quantity">Quantity</th>
<th class="cost">Unit Cost</th>
<th class="price">Total Amount</th>
<th class="action">Action</th>
</tr>
</thead>
<tbody class='line_items'>
<div id="task">
<%= f.simple_fields_for :line_items do |items| %>
<%= render 'line_item_fields', f: items %>
<% end %>
</tbody>
</table>
<div class='links'>
<%= link_to_add_association 'add item', f, :line_items, class: "btn btn-primary",data: {"association-insertion-node" => "tbody.line_items", "association-insertion-method" => "append"} %>
<%= f.submit class:"btn btn-primary" %>
</div>
</div>
<br>
This is my nested form view
<tr class="nested-fields">
<div class="container">
<div class="row row-cols-5">
<div class="col"> <td><%= f.text_field :description, class: "form-control item_desc" %></td></div><br/>
<div class="col"> <td><%= f.text_field :quantity, class: "form-control quantity" %></td></div><br/>
<div class="col"> <td><%= f.text_field :unit_cost, class: "form-control unit_cost"%></td></div><br/>
<div class="col"> <td class="price_td"><%= f.text_field :net_amount, class: "form-control price", :readonly => true %></span> <span class= "subtotal_currency"></span></td></div><br/>
<div class="col"> <td><%= link_to_remove_association 'Delete', f, class: 'remove_record btn btn-danger' %></td></div>
</div>
</div>
</tr>
This is my javascript file
function update_price(){
var row = $(this).parents('.nested-fields');
var price = row.find('.unit_cost').val() * row.find('.quantity').val();
price = price.toFixed(2);
isNaN(price) ? row.find('.price').val('is not a number') :
row.find('.price').val(price);
update_subtotal();
}
$(document).on('cocoon:after-insert', '#task', function(added_task){
// $('.links')
//('cocoon:after-insert', function(e, added_task) {
// console.log(added_task);
// })
$("#task").on('click', function(){
console.log('looks like clicking works...'); //this works fine
});
});
$(document).on('blur', '.unit_cost, .quantity', update_price)
These are the posted values to the controller
"authenticity_token"=>"qMr1sDqfOVTdjVvXzC3Hvejh3KXnoyburvHXwu7L6Qg1mSDqnagLo0gSXrUcpJumMeb1u9pPLz9OyaYndbeqBA==", "invoice"=>{"date"=>"2019/12/06","currency"=>"Naira", "line_items_attributes"=>{"0"=>{"description"=>"rice", "quantity"=>"2", "unit_cost"=>"56", "net_amount"=>"112.00", "_destroy"=>"false"}}}, "commit"=>"Create Invoice"} Unpermitted parameter: :_destroy
回答1:
From the parameters posted to the controller, we can see it is only 1 line_item
and none of the dynamically added ones.
There are a few possible reasons for this:
- using html-ids for repeating elements. For instance the nested-items are inside a encapsulating element with a fixed html-id: since repeating id's are not allowed in html, but render correctly, they are ignored when collecting the form data. Only the first element would be saved.
- another common cause is that link-to-add-association inserts the nested element on the page, and everything "looks ok", but the nested items are outside the form thus never collected when posting the form. In this case only newly added items would never be saved.
来源:https://stackoverflow.com/questions/59590890/cocoon-item-field-not-posting-values-to-database