RSS
17 Jan 2007

Mimicking ON DELETE NO ACTION / RESTRICT in Active Record

Author: ceefour | Filed under: Beginner, Complaints, Opinions, Rails, Ruby, Tips, Web 2.0

Active Record associations (has_many, has_one, belongs_to, has_and_belongs_to_many, etc.) only allows you to set :dependent as :destroy, :delete_all, or :nullify.

In the “real world”,some DBMSs (like PostgreSQL, which happen to be my favorite) allow you to have NO ACTION / RESTRICT during delete or update. Putting this on the DBMS will work most of the time. However, when you do testing with transactional fixtures, this will very likely cause problems. A failed statement will cause the transaction to “hang”, which can cause nasty error messages.

Besides, you want to handle these kinds of stuff in your Active Record model, don’t you? Here’s one quick way, use the “before_destroy” handler:

class Role :nullify # should be restrict

private
def ensure_no_users
raise ‘There are still users in this role.’ if !users.empty?
end
end

Note: You must put the “before_destroy” before the association (has_many). Otherwise it won’t work as advertised.

No related posts.

Related posts brought to you by Yet Another Related Posts Plugin.

  • http://ameilij.wordpress.com Ariel Meilij

    A nice snipplet of code. I was wondering what could happen with concurrent users on the same record, yet curiosity never made me look for an answer…

  • http://hendy.gauldong.net/ Hendy Irawan

    Dear Ariel,

    It’s “almost safe”, in that the “trigger” will be called just before the deletion is performed. So if there isn’t something that goes on the little time lapse between “check” and the deletion operation, then everything is gonna be alright… (I guess)

    A safer way would be to put the referential integrity (CONSTRAINT FOREIGN KEY ….) check also in the DBMS. (i.e. PostgreSQL and MySQL 5 supports this.) So even if something goes wrong in the application/Rails layer, the DBMS will catch it. It’s not so “DRY” (Don’t Repeat Yourself) but I think it’s a nice compromise… (and that is what I use)