Support :dependent => :restrict and :dependent => :nullify
I would love the :dependent option of AR associations to be more flexible and support :restrict and :nullify values. The first meaning that a record may not be destroyed while dependent records still exist and the second meaning that the foreign key of the dependent record is set to nil when the record in question is destroyed.
:restrict has proven to be useful in many scenarios and is also supported in sql. Furthermore, this option may improve database compatibility if ever Rails will aim to utilize database consistency checking features based on model definitions
A case for the :nullify (or :nillify) option is categories that are nested by a parent_id column where you want subcategories to become root categories when their supercategory is destroyed.
Also nullifying a foreign_key is in any case better than leaving it pointing to a non-existent record because the latter is sure to produce exceptions and may even produce an erroneous association if ever the primary key of the dependent record is reused.
10 comments
-
Stefan
commented
If I'm not completely mistaken, this has been implemented by now. Rails raises an exception when trying to delete a record which depends on other records:
"ActiveRecord::DeleteRestrictionError in XYZController#destroy
Cannot delete record because of dependent zyxs" -
PS
commented
The :restrict option would be very useful
-
mbranca
commented
+3 for that option! in DRY design is ugly to have to "embed" records validation in code or create SQL statements for that!
-
Jon Dahl
commented
ActiveRecord really should implement this. It's almost a no-brainer.
1. It's common. Every project should maintain referential integrity in some way, and :dependent => :destroy isn't always appropriate. Who wants to do a cascading delete from roles to users, or manufacturers to products, or order_statuses to orders? I don't think I've ever worked on a project where cascading deletes were always appropriate. Any lookup table, at minimum, needs this feature.
2. It fits with the Rails philosophy. Rails says "Let your application handle referential integrity, not the database". But without :dependent => :restrict, one of the most important pieces of referential integrity is missing.
3. It's easy. 9 lines of code to add this to has_many. Check out this gist:
-
Adminmattetti
(Admin, Rails)
commented
Rafael Bueno, please try to post in English, not everyone can read Portuguese.
For those you can't, Rafael created a workaround to add this kind of validation. -
Rafael Bueno
commented
Eu criei uma outra forma para fazer essa válidação.
1 - adicionei o seguinte código na minha pasta LIB
module ModelsHelper
# Classe com a minha exceção
module Exceptions
class ErrorRelashionShip < RuntimeError; end
end# Inclui os métodos de válidação restrict
module Allinclude Exceptions
# Restriction de relacionamento
def restrict_delete(relashionship_class)
if self.method(relashionship_class.class.to_s.pluralize.downcase).call.length > 0
raise ErrorRelashionShip, "O registro não pode ser removido, pois têm relacionamentos"
end
end
end
end2 - Adicionei no método :before_remove da minha model, lembrando que funciona em has_and_belongs_to_many e has_many
has_and_belongs_to_many :users, :uniq => true, :before_remove => :restrict_delete
ou
has_many :users, :before_remove => :restrict_delete
3 - Adicionei o seguinte código no meu controller
include ModelsHelper::Exceptions4 - Alterei o método destroy do controller
def destroy
@functionality = Functionality.find(params[:id])
@functionality.destroy
flash[:notice] = 'Funcionalidade deletada com sucesso'
rescue ModelsHelper::Exceptions::ErrorRelashionShip => error
flash[:notice] = error.message
ensure
redirect_to(functionalities_url)
end -
Hique
commented
I would really like to see this in Rails. Wouldn't be better, however, implement it as a validation?
-
gerjan.stokkink
commented
Heh, make that +3 :P
-
gerjan.stokkink
commented
+1 for the :restrict option :)
See also http://rails.lighthouseapp.com/projects/8994/tickets/1282-has_many-dependent-restrict.
-
Stefan Kroes commented
:dependent => :nullify already exists on has_many associations. The :restrict options would still be very useful though.