aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorRizwan Reza <rizwanreza@gmail.com>2010-03-28 18:47:46 +0430
committerRizwan Reza <rizwanreza@gmail.com>2010-03-28 18:47:46 +0430
commitf1e5a9ff982998c31c9dedf2fa79180c7dea820a (patch)
tree38857ed6fbf9cbd1ed21da13f0946b091ed516f6 /activerecord/lib/active_record
parent76f024ac8db82490a99c71d0d8951d677e3bc9bc (diff)
downloadrails-f1e5a9ff982998c31c9dedf2fa79180c7dea820a.tar.gz
rails-f1e5a9ff982998c31c9dedf2fa79180c7dea820a.tar.bz2
rails-f1e5a9ff982998c31c9dedf2fa79180c7dea820a.zip
Add :dependent = to has_one and has_many [#3075 state:resolved]
Diffstat (limited to 'activerecord/lib/active_record')
-rwxr-xr-xactiverecord/lib/active_record/associations.rb39
1 files changed, 37 insertions, 2 deletions
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 37d9c07a22..ee87cb9b41 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -86,6 +86,15 @@ module ActiveRecord
end
end
+ # This error is raised when trying to destroy a parent instance in a N:1, 1:1 assosications
+ # (has_many, has_one) when there is at least 1 child assosociated instance.
+ # ex: if @project.tasks.size > 0, DeleteRestrictionError will be raised when trying to destroy @project
+ class DeleteRestrictionError < ActiveRecordError #:nodoc:
+ def initialize(reflection)
+ super("Cannot delete record because of dependent #{reflection.name}")
+ end
+ end
+
# See ActiveRecord::Associations::ClassMethods for documentation.
module Associations # :nodoc:
extend ActiveSupport::Concern
@@ -831,6 +840,8 @@ module ActiveRecord
# objects are deleted *without* calling their +destroy+ method. If set to <tt>:nullify</tt> all associated
# objects' foreign keys are set to +NULL+ *without* calling their +save+ callbacks. *Warning:* This option is ignored when also using
# the <tt>:through</tt> option.
+ # the <tt>:through</tt> option. If set to <tt>:restrict</tt>
+ # this object cannot be deleted if it has any associated object.
# [:finder_sql]
# Specify a complete SQL statement to fetch the association. This is a good way to go for complex
# associations that depend on multiple tables. Note: When this option is used, +find_in_collection+ is _not_ added.
@@ -1469,9 +1480,15 @@ module ActiveRecord
# Creates before_destroy callback methods that nullify, delete or destroy
# has_many associated objects, according to the defined :dependent rule.
+ # If the association is marked as :dependent => :restrict, create a callback
+ # that prevents deleting entirely.
#
# See HasManyAssociation#delete_records. Dependent associations
# delete children, otherwise foreign key is set to NULL.
+ # See HasManyAssociation#delete_records. Dependent associations
+ # delete children if the option is set to :destroy or :delete_all, set the
+ # foreign key to NULL if the option is set to :nullify, and do not touch the
+ # child records if the option is set to :restrict.
#
# The +extra_conditions+ parameter, which is not used within the main
# Active Record codebase, is meant to allow plugins to define extra
@@ -1531,14 +1548,24 @@ module ActiveRecord
%@#{dependent_conditions}@)
end
CALLBACK
+ when :restrict
+ method_name = "has_many_dependent_restrict_for_#{reflection.name}".to_sym
+ define_method(method_name) do
+ unless send(reflection.name).empty?
+ raise DeleteRestrictionError.new(reflection)
+ end
+ end
+ before_destroy method_name
else
- raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, or :nullify (#{reflection.options[:dependent].inspect})"
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete_all, :nullify or :restrict (#{reflection.options[:dependent].inspect})"
end
end
end
# Creates before_destroy callback methods that nullify, delete or destroy
# has_one associated objects, according to the defined :dependent rule.
+ # If the association is marked as :dependent => :restrict, create a callback
+ # that prevents deleting entirely.
def configure_dependency_for_has_one(reflection)
if reflection.options.include?(:dependent)
name = reflection.options[:dependent]
@@ -1559,8 +1586,16 @@ module ActiveRecord
association.update_attribute(#{reflection.primary_key_name.inspect}, nil) if association
end
eoruby
+ when :restrict
+ method_name = "has_one_dependent_restrict_for_#{reflection.name}".to_sym
+ define_method(method_name) do
+ unless send(reflection.name).nil?
+ raise DeleteRestrictionError.new(reflection)
+ end
+ end
+ before_destroy method_name
else
- raise ArgumentError, "The :dependent option expects either :destroy, :delete or :nullify (#{reflection.options[:dependent].inspect})"
+ raise ArgumentError, "The :dependent option expects either :destroy, :delete, :nullify or :restrict (#{reflection.options[:dependent].inspect})"
end
before_destroy method_name