【问题标题】:How to prevent has_and_belongs_to_many delete option from deleting records that are being used in Rails?如何防止 has_and_belongs_to_many 删除选项删除 Rails 中正在使用的记录?
【发布时间】:2012-04-10 20:29:59
【问题描述】:
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 中工作。

【问题讨论】:

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


    【解决方案1】:

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

    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)

    更新

    我认为您通常不应该使用delete() 方法。你应该几乎总是使用destroy()delete() 只会触发对数据库的删除并忽略所有回调,我相信您的模型中有 :dependent =&gt; :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)的信息

    【讨论】:

      【解决方案2】:

      您需要在控制器中添加:dependent =&gt; :destroy

      【讨论】:

      • 实际上,我不想删除依赖记录,而是希望删除操作失败并闪现原因:“无法删除部件,因为它正在被一个或多个程序集使用。”
      【解决方案3】:

      您可以通过添加一些带有foreign keyreferential integrity 来阻止数据库中的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 supper 很有帮助

      我最终使用了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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多