]> source.dussan.org Git - redmine.git/commitdiff
Backported r9858 from trunk.
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Mon, 18 Jun 2012 18:29:15 +0000 (18:29 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Mon, 18 Jun 2012 18:29:15 +0000 (18:29 +0000)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.4-stable@9860 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/issue.rb
test/unit/issue_test.rb
test/unit/project_test.rb

index d72ff4dcff42ad6a9bd72f4be70eba0f0e11f0d4..3e1985a9d5623caa9a4a5b65870d756f47e8cc9f 100644 (file)
@@ -123,6 +123,28 @@ class Issue < ActiveRecord::Base
     end
   end
 
+  # AR#Base#destroy would raise and StaleObjectError exception
+  # if the issue was already deleted or updated (non matching lock_version).
+  # This is a problem when bulk deleting issues or deleting a project
+  # (because an issue may already be deleted if its parent was deleted
+  # first).
+  # The issue is reloaded by the nested_set before being deleted so
+  # the lock_version condition should not be an issue but we handle it.
+  def destroy
+    super
+  rescue ActiveRecord::StaleObjectError
+    # Stale or already deleted
+    begin
+      reload
+    rescue ActiveRecord::RecordNotFound
+      # The issue was actually already deleted
+      @destroyed = true
+      return freeze
+    end
+    # The issue was stale, retry to destroy
+    super
+  end
+
   # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
   def available_custom_fields
     (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
index b55b3d065419fd9821157da50e51195011dd95f2..698a6e70362d593c2b910ffcd86c78a9ac5fe824 100644 (file)
@@ -748,6 +748,30 @@ class IssueTest < ActiveSupport::TestCase
     assert_nil TimeEntry.find_by_issue_id(1)
   end
 
+  def test_destroying_a_deleted_issue_should_not_raise_an_error
+    issue = Issue.find(1)
+    Issue.find(1).destroy
+
+    assert_nothing_raised do
+      assert_no_difference 'Issue.count' do
+        issue.destroy
+      end
+      assert issue.destroyed?
+    end
+  end
+
+  def test_destroying_a_stale_issue_should_not_raise_an_error
+    issue = Issue.find(1)
+    Issue.find(1).update_attribute :subject, "Updated"
+
+    assert_nothing_raised do
+      assert_difference 'Issue.count', -1 do
+        issue.destroy
+      end
+      assert issue.destroyed?
+    end
+  end
+
   def test_blocked
     blocked_issue = Issue.find(9)
     blocking_issue = Issue.find(10)
index 6613ef0b2f1f12e6581a61338ccdefd0efa437e4..70b1ef8ebe82b402c8dc3388194740478d0669ad 100644 (file)
@@ -176,6 +176,18 @@ class ProjectTest < ActiveSupport::TestCase
     assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id})
   end
 
+  def test_destroy_should_destroy_subtasks
+    issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
+    issues[0].update_attribute :parent_issue_id, issues[1].id
+    issues[2].update_attribute :parent_issue_id, issues[1].id
+    assert_equal 2, issues[1].children.count
+
+    assert_nothing_raised do
+      Project.find(1).destroy
+    end
+    assert Issue.find_all_by_id(issues.map(&:id)).empty?
+  end
+
   def test_destroying_root_projects_should_clear_data
     Project.roots.each do |root|
       root.destroy