3

In a Rails app, I have foreign key constraints in MySQL which I set them all up manually, separate from my migrations.

I'm trying to figure out whether I should use ActiveRecord's :dependent => :destroy option. For example, in my schema I have tables...

users
-----

log_entries
-----------
user_id  # Has FK constraint to users.id with ON DELETE CASCADE

And in my model I could have...

class User < ActiveRecord::Base
  has_many :log_entries, :dependent => :destroy
end

Should I leave out the dependent option on the model and just leave it up to the DB? Or is it good to have that in there? I don't need to run any callbacks when deleting things in this application. In all cases it's OK to simply delete them.

Another factor to consider is that the FK constraints won't be present in my test environment probably because rake db:test:prepare doesn't set them up. So it's hard to test what happens if I'm relying totally on MySQL to cascade deletions.

Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
Ethan
  • 57,819
  • 63
  • 187
  • 237

3 Answers3

7

You shouldn't use dependent => :destroy in your models if you have FKs with ON DELETE CASCADE. It can run unnecessary queries, and you can't count on it not breaking things in the future. You should put a comment in your model file to document that it's happening. though.

I also recommend doing the FKs in the migrations. It would be much better if your test database had the same constraints as your production database, that can cause very sneaky bugs. There's a RedHill plugin (redhillonrails_core) that makes foreign keys in migrations easy, and enables schema dumps with FK constraints, so testing is much simpler.

Ethan
  • 57,819
  • 63
  • 187
  • 237
Michael Sofaer
  • 2,927
  • 24
  • 18
  • Why can't you count on it? That's like saying you should use model.to_json cause there is not guarantee that it won't break in the future. – Aaron Rustad Jul 27 '09 at 21:56
  • If you have another layer of dependencies, and the hook decides to delete them top-down, it could wind up calling methods on nil if the records disappear when it doesn't expect them to. – Michael Sofaer Jul 27 '09 at 22:27
  • it makes sense to let your database manage your data, rather than the rails app. Seconding the usage of on delete cascade. Shouldn't setting the schema_format to :sql fix the on delete cascade not being present for test database problem? – Omar Qureshi Jul 27 '09 at 22:32
  • redhillonrails_core adds FK support to the default schema dump, I prefer that to setting the schema_format. – Michael Sofaer Jul 27 '09 at 22:47
3

I'd add :dependent => :destroy there simply because it conveys intent. More importantly, not all Databases will support DELETE CASCADE, so the database adapter will be responsible for determining how to best delete the associated records. In my opinion, it is more important to put it in the model at the very least. But putting it in both is the right answer.

Aaron Rustad
  • 2,016
  • 17
  • 25
  • Totally agree with you. I believe the APPLICATION-side model dependencies is a MUST-HAVE part because it doesn't bind app with database. And DATABASE-side cascade deleting is just insure you will not have any issues when working with database directly. – Rustam Gasanov Mar 29 '12 at 12:26
3

Depends. :dependent => :destroy will load each child model and run callbacks. ON DELETE CASCADE doesn't run any callbacks, but is lightning fast.

If you only want to get rid of the models, ON DELETE CASCADE is probably the way to go, or use :dependent => :delete_all, which will only run 1 query, instead of N+1.

François Beausoleil
  • 16,265
  • 11
  • 67
  • 90
  • 1
    In my opinion, that's the trade-off. On one hand, you have a lightning fast way to destroy data, ignoring all business rules. The other is slow (can be *real* slow), but respect business logic. Both approaches are valid to me. – lsdr Oct 28 '09 at 20:03