I want to create an Invoice
and the regarding InvoiceItems
at the same time. While Invoice has_many :invoice_items
and an InvoiceItem belongs_to :invoice
. How do I perform such action in Rails 7 so that a User can add multiple invoiceItems to their invoice via Turbo? I dont need to know how TurboStreams and stuff work, since I am familiar, but I just cant get the InvoiceItems to be created at the same time as the Invoice.
I already found this post, but could not get any useful information out of it.
Models
Invoice.rb
class Invoice < ApplicationRecord
belongs_to :project
has_many :invoice_items, foreign_key: :invoice_id # not sure if this foreign_key is necessary
accepts_nested_attributes_for :invoice_items
end
invoice_item.rb
class InvoiceItem < ApplicationRecord
belongs_to :invoice
end
Controllers
Invoice_controller.rb
def create
@project = Project.find(params[:project_id])
@client = Client.find(params[:client_id])
@invoice = @project.invoices.new(invoice_params)
@invoice_item = @invoice.invoice_items.new
@invoice.invoice_items_attributes = [:invoice_id, :amount]
@invoice.client_id = @client.id
respond_to do |format|
if @invoice.save
....
def invoice_params
params.require(:invoice).permit(... :invoice_item, invoice_item_attributes: [:id, :invoice_id, :amount, ...])
end
Currently I try using a form_for
inside of the Invoice form like:
<%= form.fields_for @invoice.invoice_items.build do |lorem| %>
Which gives me following error in the console (but saves the invoice as expected:
Unpermitted parameter: :invoice_item. Context: { controller: InvoicesController, action: create, request: #<ActionDispatch::Request:0x000000010a0c8d88>, params: {"authenticity_token"=>"[FILTERED]", "invoice"=>{..., "invoice_item"=>{"invoice_id"=>"", "amount"=>"3"}}, "button"=>"", "controller"=>"invoices", "action"=>"create", "user_id"=>"1", "client_id"=>"1", "project_id"=>"1"} }
notice that the invoice_id is not passed to the invoice_item.
Via console something like
@invoice = Invoice.new
@invoice.invoice_items.new(amount: "3", ...)
@invoice.save!
Does work weirdly but it does not translate to my code. What am I doing wrong here?
CodePudding user response:
# invoice_item_attributes is wrong
def invoice_params
params.require(:invoice).permit(... :invoice_item, invoice_item_attributes: [:id, :invoice_id, :amount, ...])
end
Should be
# invoice_items_attributes is right
def invoice_params
params.require(:invoice).permit(... :invoice_item, invoice_items_attributes: [:id, :invoice_id, :amount, ...])
end
Notice the missing 's'. https://www.ombulabs.com/blog/learning/rails/nested-forms.html
CodePudding user response:
After following the GoRails screencast on how to properly set nested form attributes in rails, I still came across errors. I eventually could trace them and found this neat post which game the hint to use inverse_of
and autosave: true
. I am not 100% sure what those do, even though I will read now to find out, but my stuff is working properly now :)
Modified Model
class Invoice < ApplicationRecord
belongs_to :project
has_many :invoice_items, inverse_of: :invoice, autosave: true
accepts_nested_attributes_for :invoice_items
...