2006年4月28日 星期五

关联不再是 :dependent => true 了

作者:marcel

在 1.1 版本之前,当拥有者本身被销毁时,自动销毁 has_many 关联的方法是在声明 has_many 时使用 :dependent:exclusively_dependent 选项。


class Account < ActiveRecord::Base
  has_many :members, :dependent => true
end

或者


class Brand < ActiveRecord::Base
  has_many :products, :exclusively_dependent => true
end

:dependent 选项会实例化所有关联的对象,并对每个对象调用 destroy。destroy 又会触发在该关联模型上定义的 callback,例如用 before_destroyafter_destroy 声明的 callback。

另一方面,:exclusively_dependent 选项不会实例化所有关联的对象。它只会生成一个单独的 SQL 语句,在不先为每个记录创建对象的情况下删除关联的记录。当您不需要触发模型 callback 的灵活性时,这可以提高效率。

自 1.1 版本以来,用于垃圾回收关联记录的 API 已合并到 :dependent 选项中。现在,您不再传递 :dependent => true,而是向 :dependent 选项传递几个描述关联如何依赖于拥有者的符号之一。

将 has many 声明为 :dependent => :destroy 与以前声明为 :dependent => true 的效果相同。当拥有者被销毁时,所有关联的记录都会被实例化并销毁。


class Account < ActiveRecord::Base
  # Deprecated
  # has_many :members, :dependent => true
  
  # In favor of
  has_many :members, :dependent => :destroy
end

实现现在已弃用的 :exclusively_dependent 配置的新方法是使用 :dependent => :delete_all,而不是 :dependent => :destroy


class Brand < ActiveRecord::Base
  # Deprecated
  # has_many :products, :exclusively_dependent => true

  # In favor of
  has_many :products, :dependent => :delete_all
end

:destroy:delete_all 选项符号的命名方式是因为它们对应于在模型对象上调用 destroydelete 所达到的行为。前者触发 callback,后者仅生成 delete SQL 语句。

顺便说一下,另一个有效的选项是 :dependent => :nullify,它类似于 :dependent => :delete_all,只是它不会删除关联的记录,而是将它们的外键设置为 NULL。这有效地删除了关联,而没有从数据库表中删除关联的记录。

一如既往,:dependent => :destroy:dependent => :delete_all 的语义是互斥的,而这个新的 API 使这一点更加明显。

值得注意的是,在设置 has many 关联时,声明依赖项不是必需的。它只是一个选项,用于当您需要这种功能时。

请记住,目前 :dependent => true:exclusively_dependent => true 仍然受支持,但它们已被标记为已弃用,并可能在未来被移除。