0

請求書には多くの請求書エントリがあります:

class Invoice < ActiveRecord::Base
  has_many :invoice_entries, :autosave => true, :dependent => :destroy
  validates_presence_of :date
end

class InvoiceEntry < ActiveRecord::Base
  belongs_to :invoice
  validates_presence_of :description
end

データベースに 1 つの請求書があるとします。

id: 1
date: '2013-06-16'

2 つの請求書エントリがあります。

id: 10                           id: 11
invoice_id: 1                    invoice_id: 1
description: 'do A'              description: 'do C'

これで、新しい請求書エントリができました。

id: 10                               
description: 'do B'              description: 'do D'

(Existing invoice entry          (New invoice entry
 with updated description)        without id)

請求書にこれらの新しい請求書エントリのみを含めたい (これは、請求書エントリをid=11削除する必要があることを意味します)。

invoice.invoice_entries = new_invoice_entries仕事の半分を行うようです。で請求書エントリを削除し、説明でid=11新しい請求書エントリを作成しますが、から請求書エントリの説明を更新しません。Rails はinの存在を確認すると、それを完全に無視すると思います。本当?はいの場合、これの背後にある理論的根拠は何ですか?'Do D'id=10'Do A''Do B'idnew_invoice_entries

私の完全なコードは以下のとおりです。この問題をどのように修正しますか? (コードを簡素化する場合に備えて、Rails 4 を使用します。)


# PATCH/PUT /api/invoices/5
def update
  @invoice = Invoice.find(params[:id])
  errors = []

  # Invoice entries
  invoice_entries_params = params[:invoice_entries] || []
  invoice_entries = []

  for invoice_entry_params in invoice_entries_params
    if invoice_entry_params[:id].nil?
      invoice_entry = InvoiceEntry.new(invoice_entry_params)
      errors << invoice_entry.errors.messages.values if not invoice_entry.valid?
    else
      invoice_entry = InvoiceEntry.find_by_id(invoice_entry_params[:id])

      if invoice_entry.nil?
        errors << "Couldn't find invoice entry with id = #{invoice_entry_params[:id]}"
      else
        invoice_entry.assign_attributes(invoice_entry_params)
        errors << invoice_entry.errors.messages.values if not invoice_entry.valid?
      end
    end

    invoice_entries << invoice_entry
  end

  # Invoice
  @invoice.assign_attributes(date: params[:date])

  errors << @invoice.errors.messages.values if not @invoice.valid?

  if errors.empty?
    # Save everything
    @invoice.invoice_entries = invoice_entries
    @invoice.save

    head :no_content
  else
    render json: errors.flatten, status: :unprocessable_entity
  end
end
4

2 に答える 2

0

関連付けだけでなく、関連付けられたオブジェクトの属性も変更するには、次を使用する必要がありますaccepts_nested_attributes_for

class Invoice < ActiveRecord::Base
  has_many :invoice_entries, :autosave => true, :dependent => :destroy
  validates_presence_of :date
  accepts_nested_attributes_for :invoice_entries, allow_destroy: true
end

を使用して動的にネストされたフォームを作成する方法に関するRailscast エピソード 196がありnested_attributesます。

補遺:

accepts_nested_attributes_forネストされたハッシュ内のネストされたモデルの属性を期待します。つまり:

invoice_params={"date" => '2013-06-16', 
  "invoice_entries_attributes" => [
    {"description" => "do A"},
    {"description" => "do B"}]
}

invoice= Invoice.new(invoice_params)
invoice.save

saveセーブとinvoice2つinvoice_items

invoice=Invoice.find(1)
invoice_params={
  "invoice_entries_attributes" => [
    {"description" => "do A"},
    {"description" => "do C"}]
}
invoice.update_attributes(invoice_params)

アイテムを削除し、アイテムdo Bを追加しますdo C

form_fieldsそのようなネストされたハッシュを正確に生成するフォームを作成するために使用できます。
詳細はレールキャストをご覧ください。

于 2013-06-16T14:32:20.013 に答える