2

我正在创建一个 Category 模型并使用awesome_nested_set插件(替代acts_as_nested_set)来处理层次结构。使用awesome_nested_set,创建对象,然后保存,然后放置在集合中。同样lftrgtparent_idareattr_protected所以它们不能被直接写入。

将节点放入我希望能够捕获的集合中时,我遇到了两种情况,以便通知用户(可能还有更多我还没有想到的):

  1. 尝试将节点作为自己的子节点放置 ( self.id == self.parent_id)
  2. 试图将一个节点移动到它自己的后代之下 ( self.descendants.include? self.parent_id == true)

在这两种情况下,移动都会失败,但awesome_nested_set只会引发ActiveRecord::ActiveRecordError异常,并且消息的描述性不如我希望能够给用户的那样。

awesome_nested_set有许多节点移动方法,它们都调用move_to(target, position)(其中position一个是:root、或:child,并且是所有s 的相关节点,但)。该方法会触发回调,但没有提供一种我可以看到的在移动发生之前验证移动的方法。为了验证移动,我需要访问回调未收到的目标和位置。:left:righttargetposition:rootbefore_move

有谁知道验证移动的awesome_nested_set方法(通过一种方法将目标和位置传递给before_move另一种方法的回调),或者另一个可以让我验证的嵌套集插件?我不想分叉或编写自己的插件。

4

1 回答 1

3

这是我想出的解决方案:

class Category < ActiveRecord::Base
  acts_as_nested_set :dependent => :destroy

  #=== Nested set methods ===

  def save_with_place_in_set(parent_id = nil)
    Category.transaction do
      return false if !save_without_place_in_set
      raise ActiveRecord::Rollback if !validate_move parent_id

      place_in_nested_set parent_id
      return true
    end

    return false
  end

  alias_method_chain :save, :place_in_set

  def validate_move(parent_id)
    raise ActiveRecord::RecordNotSaved, "record must be saved before moved into the nested set" if new_record?
    return true if parent_id.nil?

    parent_id = parent_id.to_i

    if self.id == parent_id
      @error = :cannot_be_child_of_self
    elsif !Category.all.map(&:id).include?(parent_id)
      @error = :given_parent_is_invalid
    elsif descendants.map(&:id).include? parent_id
      @error = :cannot_be_child_of_descendant
    end

    errors.add(:parent_id, @error) if @error
    return @error.nil?
  end

  def place_in_nested_set(parent_id)
    if parent_id.nil? || parent_id.blank?
      move_to_root
    else
      move_to_child_of parent_id
    end
    return true
  end
end

现在,在控制器中,我只需要说父节点的ID@category.save(parent_id)在哪里,验证、节点放置和保存都在模型中处理。parent_idnil

于 2009-06-29T19:00:50.863 回答