Rails Ancestry总结所有节点

时间:2015-02-12 12:59:56

标签: ruby-on-rails-4 recursion ancestry

我正在使用the Ancestry gem。每个节点都有一个与之关联的数值(:value)。每次我CRUD一个节点,我想重新计算整个树,以便每个节点最终得到其子节点的总和。 (叶节点保持不变。)

我的控制器操作包含此代码以触发重新计算:

def create
  ...
  @tree = Tree.new(tree_params)
  if @tree.save
    Tree.roots.each do |r|
      recalc_tree(r)        
    end
    redirect_to trees_url, notice: "Node was successfully created. " + note.to_s
  else
    render :new, notice: "There was an error saving this node. Please try again."
end

并且在控制器底部的私有部分中我有这个自定义辅助方法:

def recalc_tree(r)
    total = 0
    if r.has_children?
        r.children.each do |c|
            total = total + recalc_tree(c)
        end
        r.value = total
    else
        r.value
    end
end

我没有在浏览器中收到任何错误(节点正确保存),但这也不会更新祖先节点的任何值。

我尝试在控制台中运行帮助程序,但得到了一个"未定义的方法"错误:

>> helper.recalc_tree(Tree.roots.first)

Tree Load (0.0ms)  SELECT  "trees".* FROM "trees"  WHERE "trees"."ancestry" IS NULL  ORDER BY "trees"."id" ASC LIMIT 1
NoMethodError: undefined method `recalc_tree' for #<ActionView::Base:0x5fc82c0>

我做错了什么?

1 个答案:

答案 0 :(得分:1)

更多rails风格的方法是使用ActiveRecord的回调(http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html)。此外,由于更新节点时,只需更新更新节点的祖先,因此我们可以通过仅更新根路径上的祖先来节省一些CPU周期。

示例:

class Tree < ActiveRecord::Base
  after_save :update_ancestors
  ...
  ...

  private
  def update_ancestors
    self.ancestors.each do |ancestor|
      ancestor.value = ancestor.descendants.pluck(:value).sum
      ancestor.save
    end
  end
end

我实际上没有在我的机器上运行此代码,但这几乎是这个问题的方向!