如何防止has_and_belongs_to_many删除选项删除Rails中使用的记录?

时间:2012-04-10 20:29:59

标签: ruby-on-rails ruby-on-rails-3 activerecord has-and-belongs-to-many

class Assembly < ActiveRecord::Base
  has_and_belongs_to_many :parts
end

class Part < ActiveRecord::Base
  has_and_belongs_to_many :assemblies
end

在控制台中:

part1 = Part.new
assembly1 = Assembly.new
assembly1.parts << part1
part1.delete
Parts.all
 => []

检查assembly1.parts表示仍有关系。(!)

删除记录后如何实现?

另外,如何防止删除与程序集关联的部件?

使用Rails 3.0.7。

3 个答案:

答案 0 :(得分:3)

你在这里所做的一切都是从内存中完成的(没有任何内容存储在数据库中)。

ActiveRecord delete方法将从数据库中删除一个对象,但它不会在内存中寻找可能已经引用该对象的其他对象。我想如果你做assembly1.parts.delete(part1)可能会做你期望的事情。

如果您已将对象保存到数据库:

part1 = Part.create
assembly1 = Assembly.create(:parts => [part1])
assembly1.parts
# => [part1]
part1.delete
assembly1.parts
# => [part1]
assembly1.reload
assembly1.parts
# => []

请注意,即使它在数据库part1.delete中也不一定会从汇编对象中删除它,直到您刷新内存中集合或使用我之前提到的方法删除它assembly1.parts.delete(part1) < / p>

更新

我认为通常不应使用delete()方法。您应该几乎总是使用destroy()delete()将触发对数据库的删除并忽略所有回调,我相信模型中的:dependent => :destroy - 样式声明。如果您使用destroy()方法,则可以在模型中声明before_destroy回调:

class MyClass
  has_and_belongs_to_many :foos

  before_destroy :allow_destroy

  def allow_destroy
    foos.empty?
  end
end

如果它是装配的一部分,那么你应该要求不要销毁它。您无法阻止delete()执行,因为它会忽略回调:ActiveRecord::Relation#delete documentation

有关model callbacks (documentation)

的更多信息

答案 1 :(得分:0)

您需要将:dependent => :destroy添加到控制器。

答案 2 :(得分:0)

您可以通过在referential integrity中添加foreign key来防止数据库中的myobject.delete。 建议您查看Adding foreign key to a rails model

在我的项目中,这并没有阻止myobject.destroy。我认为这是因为它确实使用awesome nested set gem尝试为您处理级联破坏。

防止myobject.destroy 我发现How do I 'validate' on destroy in rails晚餐会有所帮助

我最终使用了before_destroy并在迁移中使用add_foreign_key添加了一些参照完整性。 如果使用myobject.delete或使用myobject.destroy,这将防止删除。

在我的情况下,

myobject具有许多自身并属于其中一种。 act_as_nested_set就是这样。

模型

class Myobject
  before_destroy :allow_destroy
  # ^ this has to be above act_as_nested_set
  acts_as_nested_set

  def allow_destroy
    return true if self.descendants.blank?
    # the error is optional. 
    self.errors.add('Cannot_delete', 'myobject still has children')
    throw(:abort)
  end
end

迁移

class AddForignKeyToMyobject < ActiveRecord::Migration
  def change
    add_foreign_key :myobject, :myobject, column: :parent_id
  end
end