views:

1174

answers:

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.

+1  A: 

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.

BigCanOfTuna
+3  A: 

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.

Michael Sofaer
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.
BigCanOfTuna
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
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
redhillonrails_core adds FK support to the default schema dump, I prefer that to setting the schema_format.
Michael Sofaer
+2  A: 

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