In the Rails 3 timeframe, I would like Rails to...

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.

336 votes
Sign in
or sign in with
  • facebook
  • google
    Password icon
    Signed in as (Sign out)
    You have left! (?) (thinking…)
    Stefan Kroes shared this idea  ·   ·  Flag idea as inappropriate…  ·  Admin →


    Sign in
    or sign in with
    • facebook
    • google
      Password icon
      Signed in as (Sign out)
      • Stefan commented  ·   ·  Flag as inappropriate

        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"

      • mbranca commented  ·   ·  Flag as inappropriate

        +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  ·   ·  Flag as inappropriate

        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  ·   ·  Flag as inappropriate

        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  ·   ·  Flag as inappropriate

        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

        # Inclui os métodos de válidação restrict
        module All

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


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


        has_many :users, :before_remove => :restrict_delete

        3 - Adicionei o seguinte código no meu controller
        include ModelsHelper::Exceptions

        4 - Alterei o método destroy do controller
        def destroy
        @functionality = Functionality.find(params[:id])
        flash[:notice] = 'Funcionalidade deletada com sucesso'

        rescue ModelsHelper::Exceptions::ErrorRelashionShip => error
        flash[:notice] = error.message


      • Hique commented  ·   ·  Flag as inappropriate

        I would really like to see this in Rails. Wouldn't be better, however, implement it as a validation?

      • Stefan Kroes commented  ·   ·  Flag as inappropriate

        :dependent => :nullify already exists on has_many associations. The :restrict options would still be very useful though.

      Feedback and Knowledge Base