Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

belongs_to supports :dependent => :destroy and :delete. Closes #10592.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@8675 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
  • Loading branch information...
commit 16b129a68ca1770815107a3edb54090282349ba7 1 parent f95ff8d
@jeremy jeremy authored
View
2  activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* belongs_to supports :dependent => :destroy and :delete. #10592 [Jonathan Viney]
+
* Introduce preload query strategy for eager :includes. #9640 [Frederick Cheung, Aleksey Kondratenko]
* Support aggregations in finder conditions. #10572 [Ryan Kinderman]
View
19 activerecord/lib/active_record/associations.rb
@@ -792,6 +792,10 @@ def has_one(association_id, options = {})
# * <tt>:foreign_key</tt> - specify the foreign key used for the association. By default this is guessed to be the name
# of the association with an +_id+ suffix. So a class that defines a +belongs_to :person+ association will use +person_id+ as the default +foreign_key+.
# Similarly, +belongs_to :favorite_person, :class_name => "Person"+ will use a foreign key of +favorite_person_id+.
+ # * <tt>:dependent</tt> - if set to <tt>:destroy</tt>, the associated object is destroyed when this object is. If set to
+ # <tt>:delete</tt>, the associated object is deleted *without* calling its destroy method. This option should not be specified when
+ # <tt>belongs_to</tt> is used in conjunction with a <tt>has_many</tt> relationship on another class because of the potential to leave
+ # orphaned records behind.
# * <tt>:counter_cache</tt> - caches the number of belonging objects on the associate class through the use of +increment_counter+
# and +decrement_counter+. The counter cache is incremented when an object of this class is created and decremented when it's
# destroyed. This requires that a column named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging +Comment+ class)
@@ -876,6 +880,8 @@ def belongs_to(association_id, options = {})
"#{reflection.class_name}.send(:attr_readonly,\"#{cache_column}\".intern) if defined?(#{reflection.class_name}) && #{reflection.class_name}.respond_to?(:attr_readonly)"
)
end
+
+ configure_dependency_for_belongs_to(reflection)
end
# Associates two classes via an intermediate join table. Unless the join table is explicitly specified as
@@ -1202,6 +1208,19 @@ def configure_dependency_for_has_one(reflection)
end
end
+ def configure_dependency_for_belongs_to(reflection)
+ if reflection.options.include?(:dependent)
+ case reflection.options[:dependent]
+ when :destroy
+ module_eval "before_destroy '#{reflection.name}.destroy unless #{reflection.name}.nil?'"
+ when :delete
+ module_eval "before_destroy '#{reflection.class_name}.delete(#{reflection.name}.id) unless #{reflection.name}.nil?'"
+ else
+ raise ArgumentError, "The :dependent option expects either :destroy or :delete (#{reflection.options[:dependent].inspect})"
+ end
+ end
+ end
+
def create_has_many_reflection(association_id, options, &extension)
options.assert_valid_keys(
:class_name, :table_name, :foreign_key,
View
19 activerecord/test/cases/associations_test.rb
@@ -470,7 +470,7 @@ def test_save_still_works_after_accessing_nil_has_one
class HasManyAssociationsTest < ActiveSupport::TestCase
fixtures :accounts, :companies, :developers, :projects,
- :developers_projects, :topics, :authors, :comments
+ :developers_projects, :topics, :authors, :comments, :author_addresses
def setup
Client.destroyed_client_ids.clear
@@ -995,6 +995,23 @@ def test_dependent_association_respects_optional_sanitized_conditions_on_delete
assert_equal 1, Client.find_all_by_client_of(firm.id).size
end
+ def test_dependent_delete_and_destroy_with_belongs_to
+ author_address = author_addresses(:david_address)
+ assert_equal [], AuthorAddress.destroyed_author_address_ids[authors(:david).id]
+
+ assert_difference "AuthorAddress.count", -2 do
+ authors(:david).destroy
+ end
+
+ assert_equal [author_address.id], AuthorAddress.destroyed_author_address_ids[authors(:david).id]
+ end
+
+ def test_invalid_belongs_to_dependent_option_raises_exception
+ assert_raises ArgumentError do
+ Author.belongs_to :special_author_address, :dependent => :nullify
+ end
+ end
+
def test_clearing_without_initial_access
firm = companies(:first_firm)
View
2  activerecord/test/cases/json_serialization_test.rb
@@ -151,7 +151,7 @@ def test_should_allow_only_option_for_list_of_authors
def test_should_allow_except_option_for_list_of_authors
authors = [@david, @mary]
- assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id])
+ assert_equal %([{"id": 1}, {"id": 2}]), authors.to_json(:except => [:name, :author_address_id, :author_address_extra_id])
end
def test_should_allow_includes_for_list_of_authors
View
2  activerecord/test/fixtures/authors.yml
@@ -1,6 +1,8 @@
david:
id: 1
name: David
+ author_address_id: 1
+ author_address_extra_id: 2
mary:
id: 2
View
14 activerecord/test/models/author.rb
@@ -65,7 +65,8 @@ def testing_proxy_target
has_many :tags, :through => :posts # through has_many :through
has_many :post_categories, :through => :posts, :source => :categories
- belongs_to :author_address
+ belongs_to :author_address, :dependent => :destroy
+ belongs_to :author_address_extra, :dependent => :delete, :class_name => "AuthorAddress"
attr_accessor :post_log
@@ -101,6 +102,17 @@ def raise_exception(object)
class AuthorAddress < ActiveRecord::Base
has_one :author
+
+ def self.destroyed_author_address_ids
+ @destroyed_author_address_ids ||= Hash.new { |h,k| h[k] = [] }
+ end
+
+ before_destroy do |author_address|
+ if author_address.author
+ AuthorAddress.destroyed_author_address_ids[author_address.author.id] << author_address.id
+ end
+ true
+ end
end
class AuthorFavorite < ActiveRecord::Base
View
2  activerecord/test/schema/schema.rb
@@ -239,9 +239,9 @@ def create_table(*args, &block)
add_column :posts, :taggings_count, :integer, :default => 0
add_column :authors, :author_address_id, :integer
+ add_column :authors, :author_address_extra_id, :integer
create_table :author_addresses, :force => true do |t|
- t.column :author_address_id, :integer
end
create_table :author_favorites, :force => true do |t|
Please sign in to comment.
Something went wrong with that request. Please try again.