-
Notifications
You must be signed in to change notification settings - Fork 462
awesome_nested_set like methods for scriptaculous and acts_as_list
For those of you who may have come from awesome_nested_set or one of the equivalents, you would have enjoyed implied ordering, and the ability to place elements anywhere in the tree and also define their order implicitly. Since ancestry only deals with ancestry :) you need to use another plugin or gem to handle the positioning. I opted to use acts_as_list; the gem that was extracted from the rails core a while back. It is a little bit crude, but does the job. In awesome_nested_set and others we have the methods: move_to_(child,left,right)_of. I've recreated these methods below within the context of ancestry and acts_as_list. These methods ensure a clean move from one parent to the other, and also cleanly remove the node from the old list and add it to the new list.
I've also added in a sort method that works well with the awesome_nested_set way of doing things. Originally if you just used acts_as_tree and acts_as_list, scriptactulous would, by default, pass an array of id's and you could just assign each ID it's order in the array + 1. With nested_set we can't do this so we needed to have both the element being moved, plus an array of elements surrounding the element being moved. This way we can work out where the target node needs to be moved to, and use the move_to_(left,right) methods to do so. I like this method better because sometimes not all elements will be presented in the list, so it's better to just deal with what is present.
Add these methods to the model that ancestry is applied to:
# Accepts the typical array of ids from a scriptaculous sortable. It is called on the instance being moved
def sort(array_of_ids)
if array_of_ids.first == id.to_s
move_to_left_of siblings.find(array_of_ids.second)
else
move_to_right_of siblings.find(array_of_ids[array_of_ids.index(id.to_s) - 1])
end
end
def move_to_child_of(reference_instance)
transaction do
remove_from_list
self.update_attributes!(:parent => reference_instance)
add_to_list_bottom
save!
end
end
def move_to_left_of(reference_instance)
transaction do
remove_from_list
reference_instance.reload # Things have possibly changed in this list
self.update_attributes!(:parent_id => reference_instance.parent_id)
reference_item_position = reference_instance.position
increment_positions_on_lower_items(reference_item_position)
self.update_attribute(:position, reference_item_position)
end
end
def move_to_right_of(reference_instance)
transaction do
remove_from_list
reference_instance.reload # Things have possibly changed in this list
self.update_attributes!(:parent_id => reference_instance.parent_id)
if reference_instance.lower_item
lower_item_position = reference_instance.lower_item.position
increment_positions_on_lower_items(lower_item_position)
self.update_attribute(:position, lower_item_position)
else
add_to_list_bottom
save!
end
end
end