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
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

 

Search

A picture of me

I am François Beausoleil, a Ruby on Rails coder. During the day, I work on XLsuite. At night, I am interested many things. Read my biography

Tags

(3) (1) (0) (2) (1) (1) (2) (2) (1) (2) (1) (2) (1) (2) (1) (1) (1) (1) (2) (14) (1) (1) (1) (1) (2) (1) (1) (2) (0) (1) (2) (1) (3) (1) (1) (1) (1) (1) (1) (0) (3) (2) (1) (2) (2) (1) (3) (2) (8) (8) (9) (12) (1) (1) (3) (1) (1) (1) (1) (1) (1) (2) (2) (2) (1) (1) (3) (1) (3) (1) (0) (23) (1) (1) (0) (1) (1) (1) (23) (25) (1) (1) (13) (1) (1) (2) (3) (1) (1) (4) (1) (2) (3) (0) (1) (7) (3) (1) (5) (5) (2) (2) (2) (4) (6) (7) (1) (0) (1) (1) (2) (2) (1) (4) (12) (2) (1) (2) (4) (1) (1) (1) (2) (8) (2) (3) (2) (2) (1) (3) (1) (1)

Links

Projects I work on

Categories

Archives