awesome_nested_set like methods for scriptaculous and acts_as_list
Clone this wiki locally
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