diff -r bc0cc30635db app/models/project.rb --- a/app/models/project.rb Thu Aug 02 17:37:03 2012 +0000 +++ b/app/models/project.rb Sat Aug 04 21:18:46 2012 -0400 @@ -58,7 +58,7 @@ :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id' - acts_as_nested_set :order => 'name', :dependent => :destroy + acts_as_nested_set :order => 'name', :compare_method => lambda { |a,b| a.to_s.downcase > b.to_s.downcase }, :dependent => :destroy acts_as_attachable :view_permission => :view_files, :delete_permission => :manage_files @@ -367,6 +367,11 @@ end set_parent!(p) end + + def nested_set_rebuild(parent_node) + update_node_order(parent_node) + Issue.update_versions_from_hierarchy_change(self) + end # Sets the parent of the project # Argument can be either a Project, a String, a Fixnum or nil @@ -383,23 +388,7 @@ # Nothing to do true elsif p.nil? || (p.active? && move_possible?(p)) - # Insert the project so that target's children or root projects stay alphabetically sorted - sibs = (p.nil? ? self.class.roots : p.children) - to_be_inserted_before = sibs.detect {|c| c.name.to_s.downcase > name.to_s.downcase } - if to_be_inserted_before - move_to_left_of(to_be_inserted_before) - elsif p.nil? - if sibs.empty? - # move_to_root adds the project in first (ie. left) position - move_to_root - else - move_to_right_of(sibs.last) unless self == sibs.last - end - else - # move_to_child_of adds the project in last (ie.right) position - move_to_child_of(p) - end - Issue.update_versions_from_hierarchy_change(self) + nested_set_rebuild(p) true else # Can not move to the given target @@ -407,6 +396,15 @@ end end + def save + changed = name_changed? + ret_val = super + if changed + nested_set_rebuild(parent) + end + ret_val + end + # Returns an array of the trackers used by the project and its active sub projects def rolled_up_trackers @rolled_up_trackers ||= diff -r bc0cc30635db lib/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb --- a/lib/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb Thu Aug 02 17:37:03 2012 +0000 +++ b/lib/plugins/awesome_nested_set/lib/awesome_nested_set/awesome_nested_set.rb Sat Aug 04 21:18:46 2012 -0400 @@ -380,6 +380,34 @@ end.join("\n") end + def update_node_order(parent_node) + order = acts_as_nested_set_options[:order] + method = acts_as_nested_set_options[:compare_method] + sibs = (parent_node.nil? ? self.class.roots : parent_node.children) + to_be_inserted_before = sibs.detect {|c| + a = c.read_attribute("#{order}") + b = read_attribute("#{order}") + if method.nil? + a > b + else + method.call(a,b) + end + } + if to_be_inserted_before + move_to_left_of(to_be_inserted_before) + elsif parent_node.nil? + if sibs.empty? + # move_to_root adds the node in first (ie. left) position + move_to_root + else + move_to_right_of(sibs.last) unless self == sibs.last + end + else + # move_to_child_of adds the node in last (ie.right) position + move_to_child_of(parent_node) + end + end + protected def without_self(scope) diff -r bc0cc30635db test/unit/project_test.rb --- a/test/unit/project_test.rb Thu Aug 02 17:37:03 2012 +0000 +++ b/test/unit/project_test.rb Sat Aug 04 21:18:46 2012 -0400 @@ -775,6 +775,35 @@ assert !project.activities.include?(system_activity), "System activity found when the project has an inactive override" end + # See issue #11508, updating a project does not reorder sibilings alphabetically. + def test_rebuild_should_sort_children_alphabetically_on_update + ProjectCustomField.delete_all + + # Create 4 projects under a parent project. + parent = Project.create!(:name => 'Parent', :identifier => 'parent') + Project.create!(:name => 'Project C', :identifier => 'project-c').move_to_child_of(parent) + Project.create!(:name => 'Project B', :identifier => 'project-b').move_to_child_of(parent) + Project.create!(:name => 'Project D', :identifier => 'project-d').move_to_child_of(parent) + renamed_project = Project.create!(:name => 'Project A', :identifier => 'project-a').move_to_child_of(parent) + + # Rebuild them all. + Project.update_all("lft = NULL, rgt = NULL") + Project.rebuild! + + # Confirm that everything is as expected. + all_projects = Project.find(:all, :order => 'lft') + assert_equal 'Project D', all_projects.last.name + + # Load and modify project-a, which causes defect #11508 + project = Project.find_by_id(renamed_project.id) + project.name = 'Project E' + assert_equal true, project.save + + # Reload all projects and verify that "Project E" is last. + all_projects = Project.find(:all, :order => 'lft') + assert_equal 'Project E', all_projects.last.name + end + def test_close_completed_versions Version.update_all("status = 'open'") project = Project.find(1)