How to prevent ActiveRecord instance destruction
November 21st, 2005
In one of my projects, I wanted to prevent instances of particular classes to be deleted if they were in any way associated to another object. In database terms, I wanted an ON DELETE RESTRICT constraint.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
require File.dirname(__FILE__) + '/../test_helper' class CityTest < Test::Unit::TestCase fixtures :cities, :contacts def setup @city = City.find(:first) end def test_prevent_destruction_if_associated_to_any_contact @city.contacts << contacts(:jill) @city.destroy assert_not_nil City.find(@city.id), 'should not have been destroyed' assert_match /cannot destroy.*contacts/i, @city.errors.on_base, 'reports error condition to user' end def test_allow_destruction_if_not_associated_to_any_contact @city.destroy assert_raises ActiveRecord::RecordNotFound do City.find(@city.id) end end end |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class City < ActiveRecord::Base has_and_belongs_to_many :contacts, :join_table => 'contacts_cities' def destroy unless self.contacts.empty? self.errors.add_to_base \ 'We cannot destroy this instance since one or more contacts refer to it') return end super end end |
I had to override destroy because in has_and_belongs_to_many relationships, Rails deletes join table records before deleting the record. This means that in before_destroy filters, self.contacts.empty? will always report true. Ticket #1183: dependents are destroyed before client before_destroy hooks are called is already opened on this issue.
UPDATE (2006-03-08) Fixed since 2006-02-13