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.

Since I cannot rely on the database to enforce it for me (MySQL 4, MyISAM engine), I coded the following:

 1 require File.dirname(__FILE__) + '/../test_helper'
 3 class CityTest < Test::Unit::TestCase
 4   fixtures :cities, :contacts
 6   def setup
 7     @city = City.find(:first)
 8   end
10   def test_prevent_destruction_if_associated_to_any_contact
11     @city.contacts << contacts(:jill)
12     @city.destroy
13     assert_not_nil City.find(, 'should not have been destroyed'
14     assert_match /cannot destroy.*contacts/i, @city.errors.on_base,
15         'reports error condition to user'
16   end
18   def test_allow_destruction_if_not_associated_to_any_contact
19     @city.destroy
20     assert_raises ActiveRecord::RecordNotFound do
21       City.find(
22     end
23   end
24 end

 1 class City < ActiveRecord::Base
 2   has_and_belongs_to_many :contacts, :join_table => 'contacts_cities'
 4   def destroy
 5     unless self.contacts.empty?
 6       self.errors.add_to_base \
 7           'We cannot destroy this instance since one or more contacts refer to it')
 8       return
 9     end
11     super
12   end
13 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


Your Host

A picture of me

I am François Beausoleil, a Ruby on Rails and Scala developer. During the day, I work on Seevibes, a platform to measure social interactions related to TV shows. At night, I am interested many things. Read my biography.

Top Tags

Books I read and recommend


Projects I work on

Projects I worked on