rails acts_as_nested_set with uniqueness

508 Views Asked by At

I'm using acts_as_nested_set on a model which is called node. There are multiple lists stored in the database, each starting with the root node. The root node doesn't have a parent, that's how I know it's a root.

Now this all works as expected, but the problem is this:

All nodes have an alias, which needs to be unique in that list.

So, all children of a root have a unique alias, but all nodes are in a single db-table.

Does anyone know a solution for checking uniqueness only in the tree the node is in?

EDIT:

As Baldrick points out I'd be off good using a custom validation. The problem is, in the validation root returns nil. As shown below:

class Baco::Node < ActiveRecord::Base

  set_table_name "baco_nodes"

  acts_as_nested_set :order => :position

  acts_as_list :scope => :parent_id

  default_scope order("parent_id, position")

  validate :alias_uniqueness

  def alias_uniqueness

    p self.parent.parent       # return the root
    p self.parent              # returns the parent
    p self.root                # returns nil

    if parent.nil?
      root = self
    else
      root = self.parent.root
    end

    if root.descendants.index { |node| node != self && node.alias == self.alias }
      errors.add(:alias, "Alias already used")
    end
  end

end

EDIT 2

The problem appeared when creating a child. So it's a new node that only has a parent yet, but no left and right values.. Instead of getting the root of the new node I now get the root of it's parent, which of course would be the same.. So the custom validation above works now.

Thanks

1

There are 1 best solutions below

7
On BEST ANSWER

Use a custom validation method to check that the alias is not already used by a node descendant of the same root:

class Node < ActiveRecord::Base
  validate :alias_uniqueness

  def alias_uniqueness
    if self.root.descendants.index {|node| node != self && node.alias == self.alias}
      errors.add(:alias, "Alias already used")
    end
  end

  ...
end