protected_parent_of

Stops the deletion of an ActiveRecord object when members of a specified child association exist.

It adds a "removeable?" method to evaluate whether the object may be deleted and the necessary before_destroy callback.

Example Usage

Adding to your models

The model 'has_many :posts'. Do not allow deletion if there are Post records associated with this object:

class Category < ActiveRecord::Base
  protected_parent_of :posts
end

If it 'has_one :attachement', don't allow deletion until the attachment has been removed. Use the singular, just like the 'has_one'

class Category < ActiveRecord::Base
  protected_parent_of :attachment
end

If necessary, allow several child objects to stay deletion. For example, a polymorphic category model may have:

class Category < ActiveRecord::Base
  protected_parent_of :posts, :comments
end

Depending on taste, you can call protected_parent_of multiple times:

class Category < ActiveRecord::Base
  has_many :posts
  has_many :comments
  protected_parent_of :posts, :comments

  has_one :attachment
  protected_parent_of :attachment
end

When you need something more sophisticated, you can target a method or named_scope. This would block deletion of the category if there were any active posts:

class Category < ActiveRecord::Base
  has_many :posts
  protected_parent_of :active_posts

  def active_posts
    posts.active
  end
end

class Post < ActiveRecord::Base
  named_scope :active, :condition => { :active => true }
end

Using the methods

Once applied to a model, protected_parent_of adds several methods to your model. You can now use 'protected?' and 'removable?'

category = Category.new
category.protected?                 # False
category.removable?                 # True

category = Category.new
category.posts << Post.create
category.protected?                 # True
category.removable?                 # False

And most importantly, it will block deletion

category = Category.create
category.posts = Post.create
category.delete                     # False
category.delete!                    # Raises an exception

License

Copyright (c) 2010 Tim Harvey, released under the MIT license