Skip to content

Commit

Permalink
Merge pull request rails#6629 from marcandre/destroy
Browse files Browse the repository at this point in the history
Add ActiveRecord::Base#destroy!
  • Loading branch information
carlosantoniodasilva committed Jun 6, 2012
2 parents b4fb80c + 4faaa81 commit e638c61
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 0 deletions.
5 changes: 5 additions & 0 deletions activerecord/CHANGELOG.md
@@ -1,5 +1,10 @@
## Rails 4.0.0 (unreleased) ##

* Added `#destroy!` which acts like `#destroy` but will raise an
`ActiveRecord::RecordNotDestroyed` exception instead of returning `false`.

*Marc-André Lafortune*

* Allow blocks for `count` with `ActiveRecord::Relation`, to work similar as
`Array#count`:

Expand Down
4 changes: 4 additions & 0 deletions activerecord/lib/active_record/errors.rb
Expand Up @@ -53,6 +53,10 @@ class RecordNotFound < ActiveRecordError
class RecordNotSaved < ActiveRecordError
end

# Raised by ActiveRecord::Base.destroy! when a call to destroy would return false.
class RecordNotDestroyed < ActiveRecordError
end

# Raised when SQL statement cannot be executed by the database (for example, it's often the case for
# MySQL when Ruby driver used is too old).
class StatementInvalid < ActiveRecordError
Expand Down
16 changes: 16 additions & 0 deletions activerecord/lib/active_record/persistence.rb
Expand Up @@ -122,6 +122,11 @@ def delete

# Deletes the record in the database and freezes this instance to reflect
# that no changes should be made (since they can't be persisted).
#
# There's a series of callbacks associated with <tt>destroy</tt>. If
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
# and <tt>destroy</tt> returns +false+. See
# ActiveRecord::Callbacks for further details.
def destroy
raise ReadOnlyRecord if readonly?
destroy_associations
Expand All @@ -130,6 +135,17 @@ def destroy
freeze
end

# Deletes the record in the database and freezes this instance to reflect
# that no changes should be made (since they can't be persisted).
#
# There's a series of callbacks associated with <tt>destroy!</tt>. If
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
# ActiveRecord::Callbacks for further details.
def destroy!
destroy || raise(ActiveRecord::RecordNotDestroyed)
end

# Returns an instance of the specified +klass+ with the attributes of the
# current record. This is mostly useful in relation to single-table
# inheritance structures where you want a subclass to appear as the
Expand Down
2 changes: 2 additions & 0 deletions activerecord/test/cases/callbacks_test.rb
Expand Up @@ -426,11 +426,13 @@ def test_before_update_returning_false
def test_before_destroy_returning_false
david = ImmutableDeveloper.find(1)
assert !david.destroy
assert_raise(ActiveRecord::RecordNotDestroyed) { david.destroy! }
assert_not_nil ImmutableDeveloper.find_by_id(1)

someone = CallbackCancellationDeveloper.find(1)
someone.cancel_before_destroy = true
assert !someone.destroy
assert_raise(ActiveRecord::RecordNotDestroyed) { someone.destroy! }
assert !someone.after_destroy_called
end

Expand Down
7 changes: 7 additions & 0 deletions activerecord/test/cases/persistence_test.rb
Expand Up @@ -305,6 +305,13 @@ def test_destroy
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
end

def test_destroy!
topic = Topic.find(1)
assert_equal topic, topic.destroy!, 'topic.destroy! did not return self'
assert topic.frozen?, 'topic not frozen after destroy!'
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
end

def test_record_not_found_exception
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(99999) }
end
Expand Down

0 comments on commit e638c61

Please sign in to comment.