after_destroy上的Nil对象

时间:2009-07-02 16:53:41

标签: ruby-on-rails activerecord

我有一个方法,只要创建或销毁依赖项,就会更新父类的依赖对象的数量。这通常有效,但出于某种原因,当父类被第三类删除时,使用:dependent => :destroy,当调用count方法时,我得到父对象的nil错误,因此没有任何内容被删除。如果我在此操作期间尝试从count方法提升parent.inspect,则会返回它,因此它显然不是nil。有什么想法吗?

class DependentObject < ActiveRecord::Base
      belongs_to :parent
      belongs_to :third_object

      after_destroy :count

      def count
        count = DependentObject.count(:all, :conditions => ['parent_id = ?', self.parent_id])
        self.parent.count = count
        self.parent.save
    end

end

class Parent < ActiveRecord::Base
    belongs_to :third_object
    has_many :dependent_objects, :dependent => :delete_all
end

class ThirdObject
    has_many :parents, :dependent => :destroy
    has_many :dependent_objects, :dependent => :destroy

end
编辑:我之所以:dependent =&gt;父方法中的delete_all是我天真地假设,因为:delete_all不会触发:after_destroy并且只会在父类被销毁时被调用,它会避免这个问题。查看开发日志,确实是这种情况,因为它在所有相关对象中显示“DependentObject Delete all”,然后再执行“DependentObject Destroy all”并遇到nil错误并启动回滚。

1 个答案:

答案 0 :(得分:4)

ActiveRecord喜欢缓存已使用的关联对象。我想这可能就是你的问题所在。 执行third_obj.dependent_objects时,对象将加载到内存中并进行缓存。然后当你摧毁third_obj时,它会摧毁parents然后摧毁dependent_objects。但是如果有缓存的obj,而不是从db中加载它们来销毁它们,它会在缓存版本上调用destroy,它具有陈旧的父ID,并且已经不再存在于db中。

解决此问题的一种方法是重新排序has_many声明,以便以其他顺序调用destroys。

    has_many :dependent_objects, :dependent => :destroy
    has_many :parents, :dependent => :destroy

这会有一些额外的sql调用,但不会有nil问题。 但是有更好的方法来计算事物。 e.g。

parent.dependent_objects.count #does a sql count query--much faster
                               #than loading all the obj in memory

您还可以在父{q}个:counter_cache => true声明中使用has_many :dependent_objects选项,并在父表dependent_objects_count

中添加一列