Nested Sets and Scope
October 3rd, 2008
A colleague and I both had this same issue working with BNS and since there wasn’t much about it on the net, I figured I’d share.
Each TLD in my nested set will be its own tree root. And multiple tree roots in a nested set require a scope.
acts_as_nested_set :scope => :root
The ruby on rails wiki mentions scope using a root_id column, but you’ll notice in the example that the root records have a root_id of nil. This just doesn’t work.
When you attempt to move_to_child_of your new node record after create, you’ll recieve this error:
Impossible move, target node cannot be inside moved tree.
Now, we couldn’t find any documentation anywhere but after much trial and error my colleague discovered that populating the root_id of a root record with its own id, resolves the issue.
root = Domain.new
subdomains.each_with_index do |subdomain, index|
node = Domain.find_by_subdomain_and_parent_id(subdomain, parent.id)
if node.nil?
node = Domain.create(:subdomain => subdomain, root_id => root.id)
if parent.new_record? #is this a root record?
node.root_id = node.id # <-------------------------------- populate root for root records
node.save
root = node
else
node.move_to_child_of parent.id
end
end
parent = node
end
Entry Filed under: Ruby on Rails
2 Comments Add your own
Leave a Comment
Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>
Trackback this post | Subscribe to the comments via RSS Feed
1. hades76 | November 17th, 2008 at 6:31 pm
I’m using the same plugin / method to create scope.
And my database is good populate but how can i access a specific scope with full_set ?
Actualy i use :
MenuItem.root.full_set
(who give me only scope = 1)
2. Alex Schregardus | December 4th, 2008 at 10:04 am
Try the following in your model, works from me.
def before_create
# Update the child object with its parents attrs
unless self[:parent_id].to_i.zero?
self[:root_id] = parent[:root_id].to_i
end
end
def after_create
# Update the parent root_id with its id
if self[:parent_id].to_i.zero?
self[:root_id] = self[:id]
self.save
else
parent.add_child self
end
end
See: http://i.nfectio.us/articles/2006/03/31/implement-acts_as_threaded-without-a-plugin