Rails 5 +
[我知道destroy_all
实例化每个模型并在其上运行destroy
,并且delete_all
更快,但是删除不符合要求:
before_destroy
,around_destroy
和after_destroy
回调dependent
关系设置假设列表很全面,我们是否不应该通过检查模型的这些属性来节省destroy_all
的时间,如果没有回调,只需根据需要解决关系?
# Pseudocode
# Let the model in question be `User`
ids = self.pluck(:id)
if model.has_destroy_callbacks # I imagine there's some fancy introspection stuff I can use
original_destroy_all
return
else
# Check Restrict type
model.restrict_relationships.each do |rel|
other_models = some_cute_query
raise_exception_or_add_error if other_models.any?
end
# Add some check here to make sure we didn't miss any unknown dependency type
# Normal relationships
model.non_restrict_relationships.each do |rel|
dep_type = rel.dependent_type
if dep_type == :destroy
rel.where(model_id: ids).destroy_all
elsif dep_type == :delete
rel.where(model_id: ids).delete_all
elsif dep_type == :nullify
rel.where(model_id: ids).update_all(model_name_id: nil)
end
end
end
self.delete_all # i.e. the collection that was gonna get destroyed
我正在寻找的是健全性检查,如果我遗漏了一些明显的原因,为什么这将不起作用。我也在寻找有关如何将其填充到ActiveRecord的建议。另外,您可以为特定模型上的集合/关系专门覆盖destroy_all
吗?
回调链可通过
_*_callbacks
方法访问宾语。活动模型回调支持:before
,:after
和:around
作为kind属性的值。 kind属性定义回调在链的哪一部分运行。要在before_save回调链中找到所有回调:
Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
因此,在这种情况下,其为_destroy_callbacks
,但如果您的目标是健全性检查,则我将使该方法引发异常并保释,而不是调用destroy_all
。
raise SomeKindOfError if model._destroy_callbacks.any?
就调试和使用而言,这比埋葬问题要有用得多。
获取模型的所有关联可以通过.reflect_on_all_associations
完成,它为您提供了AssocationReflection对象。从那里可以找到关联的选项。
这有点“聪明”的代码。当您意识到使用回调是性能问题时,存在更大的问题,然后只需选择.reflect_on_all_associations
或delete_all
。