Home > Mobile >  How do i create a parent and child element at the same time rails
How do i create a parent and child element at the same time rails

Time:09-07

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
...
  • Related