保存模型时删除关联记录

ibl*_*lue 5 activerecord ruby-on-rails ruby-on-rails-3

我正在运行 ActiveRecord 3.2.6。鉴于我有这些模型定义:

我的发票模型

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
Run Code Online (Sandbox Code Playgroud)

我的物品模型

class Item < ActiveRecord::Base
  belongs_to :invoice

  attr_accessible :amount, :description, :invoice_id, :value
end
Run Code Online (Sandbox Code Playgroud)

我的目标是将发票项目直接保存在模型中。当发票是新创建的时,这可以正常工作。一通电话Invoice#save!即可保存所有内容。

> 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 
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试更新已存在的项目时Invoice,它会在保存新项目之前删除旧项目。

# 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
Run Code Online (Sandbox Code Playgroud)

如何告诉 ActiveRecord 仅在Invoice#save!调用时删除旧项目?或者这是 ActiveRecord 中的一个错误?

编辑:我的问题 - 澄清

我不希望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
Run Code Online (Sandbox Code Playgroud)

实际发生了什么

查询DELETE在点 运行(2)。但它应该在 point 运行(3)。(与上面的列表比较)。

Kri*_*ari 0

它将删除旧项目,因为您将关联配置为自动保存

has_many :items, :autosave => true, :dependent => :delete_all
Run Code Online (Sandbox Code Playgroud)

删除自动保存并重试,就可以了。