DRY: How to prevent deletion of parent if children exist?

28 views
Skip to first unread message

Michael Q

unread,
Oct 29, 2011, 5:40:33 AM10/29/11
to hobo...@googlegroups.com
What is the most DRY way to prevent deletion of a parent if children exist?

I assume it would be a
before_destroy :check_that_no_child_exists

But an object might have several different types of children and we would ideally want to iterate through all the has_many's with just one command.

Is there an elegant way of doing this, and returning a helpful error message indicating which type of child exists?

I'm amazed that Rails still doesn't seem to have a default facility for this as its a very basic requirement.

Thanks,
Michael

Peter Booth

unread,
Oct 29, 2011, 10:38:41 AM10/29/11
to hobo...@googlegroups.com, hobo...@googlegroups.com
There is a way, it just isn't part of Rails:
Database constraints. 

I've found that they help fortify my app, especially as there are sometimes times when data cleanup thru active record might take 100x more than straight SQL.

Sent from my iPhone
--
You received this message because you are subscribed to the Google Groups "Hobo Users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/hobousers/-/0Awm6SDGCM8J.
To post to this group, send email to hobo...@googlegroups.com.
To unsubscribe from this group, send email to hobousers+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/hobousers?hl=en.

Matt Jones

unread,
Oct 29, 2011, 11:32:53 AM10/29/11
to hobo...@googlegroups.com

Rails 3 added the :restrict option for dependent associations - to use it:

has_many :foos, :dependent => :restrict

Attempting to delete a model that still has associated foos will raise an ActiveRecord::DeleteRestrictionError with the message:

"Cannot delete record because of dependent #{reflection.name}"

You'll need to catch this exception (probably in your controller) and figure out how to present it to the user.

DB-level constraints are certainly another option - note that you may need to change the default schema format to :sql to be able to test them. You'll still have to catch the exception, but it will be a database-specific one.

Finally, you can prevent users *seeing* the delete option by adding code like this to the model:

def destroy_permitted?
foos.empty?
end

This will remove Rapid-generated delete buttons from your interface, and attempting to delete a record will raise a PermissionDeniedError.

--Matt Jones

Reply all
Reply to author
Forward
0 new messages