Skip to content

Commit

Permalink
Added that model.items.delete(child) will delete the child, not just …
Browse files Browse the repository at this point in the history
…set the foreign key to nil, if the child is dependent on the model #978 [bitsweat]

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@1064 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information
dhh committed Apr 2, 2005
1 parent c6cc707 commit 1ba1779
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 10 deletions.
2 changes: 2 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN* *SVN*


* Added that model.items.delete(child) will delete the child, not just set the foreign key to nil, if the child is dependent on the model #978 [bitsweat]

* Fixed auto-stamping of dates (created_on/updated_on) for PostgreSQL #985 [dave@cherryville.org] * Fixed auto-stamping of dates (created_on/updated_on) for PostgreSQL #985 [dave@cherryville.org]


* Fixed Base.silence/benchmark to only log if a logger has been configured #986 [skaes@web.de] * Fixed Base.silence/benchmark to only log if a logger has been configured #986 [skaes@web.de]
Expand Down
5 changes: 4 additions & 1 deletion activerecord/lib/active_record/associations.rb
Expand Up @@ -153,7 +153,8 @@ module ClassMethods
# * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects. # * <tt>collection(force_reload = false)</tt> - returns an array of all the associated objects.
# An empty array is returned if none are found. # An empty array is returned if none are found.
# * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key. # * <tt>collection<<(object, ...)</tt> - adds one or more objects to the collection by setting their foreign keys to the collection's primary key.
# * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL. This does not destroy the objects. # * <tt>collection.delete(object, ...)</tt> - removes one or more objects from the collection by setting their foreign keys to NULL.
# This will also destroy the objects if they're declared as belongs_to and dependent on this model.
# * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects. # * <tt>collection.clear</tt> - removes every object from the collection. This does not destroy the objects.
# * <tt>collection.empty?</tt> - returns true if there are no associated objects. # * <tt>collection.empty?</tt> - returns true if there are no associated objects.
# * <tt>collection.size</tt> - returns the number of associated objects. # * <tt>collection.size</tt> - returns the number of associated objects.
Expand Down Expand Up @@ -219,6 +220,8 @@ def has_many(association_id, options = {})


if options[:dependent] and options[:exclusively_dependent] if options[:dependent] and options[:exclusively_dependent]
raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' # ' ruby-mode raise ArgumentError, ':dependent and :exclusively_dependent are mutually exclusive options. You may specify one or the other.' # ' ruby-mode
# See HasManyAssociation#delete_records. Dependent associations
# delete children, otherwise foreign key is set to NULL.
elsif options[:dependent] elsif options[:dependent]
module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'" module_eval "before_destroy '#{association_name}.each { |o| o.destroy }'"
elsif options[:exclusively_dependent] elsif options[:exclusively_dependent]
Expand Down
Expand Up @@ -113,11 +113,15 @@ def insert_record(record)
end end


def delete_records(records) def delete_records(records)
ids = quoted_record_ids(records) if @options[:dependent]
@association_class.update_all( records.each { |r| r.destroy }
"#{@association_class_primary_key_name} = NULL", else
"#{@association_class_primary_key_name} = #{@owner.quoted_id} AND #{@association_class.primary_key} IN (#{ids})" ids = quoted_record_ids(records)
) @association_class.update_all(
"#{@association_class_primary_key_name} = NULL",
"#{@association_class_primary_key_name} = #{@owner.quoted_id} AND #{@association_class.primary_key} IN (#{ids})"
)
end
end end


def target_obsolete? def target_obsolete?
Expand Down
20 changes: 16 additions & 4 deletions activerecord/test/associations_test.rb
Expand Up @@ -481,9 +481,21 @@ def test_destroy_all
end end


def test_dependence def test_dependence
assert_equal 2, Client.find_all.length assert_equal 2, Client.find_all.size
Firm.find_first.destroy Firm.find_first.destroy
assert_equal 0, Client.find_all.length assert Client.find_all.empty?
end

def test_destroy_dependent_when_deleted_from_association
firm = Firm.find_first
assert_equal 2, firm.clients.size

client = firm.clients.first
firm.clients.delete(client)

assert_raise(ActiveRecord::RecordNotFound) { Client.find(client.id) }
assert_raise(ActiveRecord::RecordNotFound) { firm.clients.find(client.id) }
assert_equal 1, firm.clients.size
end end


def test_three_levels_of_dependence def test_three_levels_of_dependence
Expand Down Expand Up @@ -615,15 +627,15 @@ def test_assignment_before_either_saved


def test_new_record_with_foreign_key_but_no_object def test_new_record_with_foreign_key_but_no_object
c = Client.new("firm_id" => 1) c = Client.new("firm_id" => 1)
assert_equal @first_firm, c.firm_with_basic_id assert_equal Firm.find_first, c.firm_with_basic_id
end end


def test_forgetting_the_load_when_foreign_key_enters_late def test_forgetting_the_load_when_foreign_key_enters_late
c = Client.new c = Client.new
assert_nil c.firm_with_basic_id assert_nil c.firm_with_basic_id


c.firm_id = 1 c.firm_id = 1
assert_equal @first_firm, c.firm_with_basic_id assert_equal Firm.find_first, c.firm_with_basic_id
end end


def test_field_name_same_as_foreign_key def test_field_name_same_as_foreign_key
Expand Down

0 comments on commit 1ba1779

Please sign in to comment.