Delete related records while saving the model

I am running ActiveRecord 3.2.6. Given that I have these model definitions:

My account model

class Invoice < ActiveRecord::Base
  has_many :items, :autosave => true, :dependent => :delete_all
  attr_accessible :recipient_email

  # This is just a simple wrapper with allows me to build multiple
  # items at once and to specify them as a Hash instead of Item.new.
  def items=(ary)
    super ary.map{|item| item.is_a?(Hash) ? items.build(item) : item}
  end
end

Model of my product

class Item < ActiveRecord::Base
  belongs_to :invoice

  attr_accessible :amount, :description, :invoice_id, :value
end

My goal is to save the elements of the account directly in the model. This works without problems when the invoice has just been created. One call Invoice#save!and everything will be saved.

> i = Invoice.new(:recipient_email => "foobar@example.org")
> i.items = [{amount: 10, description: "Bottles of Milk", value: 0.40},
  {amount: 1, description: "Shipping fee to Antarctica", value: 217.38}]
> i.save!
  SQL (23.5ms)  INSERT INTO "invoices" [...]
  SQL (0.3ms)  INSERT INTO "items" [...]
  SQL (0.2ms)  INSERT INTO "items" [...]
 => true 

However, when I try to update items in Invoiceexisting ones, it deletes old items before saving new items.

# Load invoice ID 1, with two items: ID 1 and ID 2.
> i = Invoice.find(1)

# It deletes the old items here
> i.items = [{amount: 10, description: "Less buggy objective relational mappers", value: 1337.00}]
  SQL (0.8ms)  DELETE FROM items WHERE id IN (1, 2)

# But it should delete the new items here, before inserting the new items,
# wrapping everything in a transaction.
> i.save!
  SQL (1.0ms)  INSERT INTO "items" [...]
   (192.6ms)  commit transaction

How can I tell ActiveRecord to remove old items only when called Invoice#save!? Or is this a bug in ActiveRecord?

EDIT: My question is clarified

, DELETE (i.items = ...), , , (invoice.save!). , invoice.save!. ActiveRecord?

2:

, . , . , , .

. , . . , .

# (1) Load invoice ID 1, with two items: ID 1 and ID 2.
> i = Invoice.find(1)

# (2) Assign new items, delete the old ones. New stuff exists in memory, not in database
> i.items = [{amount: 10, description: "Less buggy objective relational mappers", value: 1337.00}]

# (3) Save everything to database. Run queries.
> i.save!
   (0.0ms) begin transactions
  SQL (0.8ms)  DELETE FROM items WHERE id IN (1, 2)
  SQL (1.0ms)  INSERT INTO "items" [...]
   (192.6ms)  commit transaction

hapens

DELETE (2). (3). ( ).

+2
2

,

has_many :items, :autosave => true, :dependent => :delete_all

, .

0

, , :

  def items=(ary)
    super(ary.map{|item| item.is_a?(Hash) ? items.build(item) : item} + self.items)
  end
0

All Articles