mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Allow :dependent options to be used with polymorphic joins. #3820 [Rick Olson]
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@3881 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
bf39c39d88
commit
0859779d6f
6 changed files with 99 additions and 9 deletions
|
@ -1,5 +1,11 @@
|
|||
*SVN*
|
||||
|
||||
* Allow :dependent options to be used with polymorphic joins. #3820 [Rick Olson]
|
||||
|
||||
class Foo < ActiveRecord::Base
|
||||
has_many :attachments, :as => :attachable, :dependent => :delete_all
|
||||
end
|
||||
|
||||
* Upgrade to Transaction::Simple 1.3 [Jamis Buck]
|
||||
|
||||
* Catch FixtureClassNotFound when using instantiated fixtures on a fixture that has no ActiveRecord model [Rick Olson]
|
||||
|
|
|
@ -485,7 +485,7 @@ module ActiveRecord
|
|||
|
||||
if association.updated?
|
||||
self["#{reflection.primary_key_name}"] = association.id
|
||||
self["#{reflection.options[:foreign_type]}"] = ActiveRecord::Base.send(:class_name_of_active_record_descendant, association.class).to_s
|
||||
self["#{reflection.options[:foreign_type]}"] = association.class.base_class.name.to_s
|
||||
end
|
||||
end
|
||||
EOF
|
||||
|
@ -811,13 +811,20 @@ module ActiveRecord
|
|||
|
||||
# See HasManyAssociation#delete_records. Dependent associations
|
||||
# delete children, otherwise foreign key is set to NULL.
|
||||
|
||||
# Add polymorphic type if the :as option is present
|
||||
dependent_conditions = %(#{reflection.primary_key_name} = \#{record.quoted_id})
|
||||
if reflection.options[:as]
|
||||
dependent_conditions += " AND #{reflection.options[:as]}_type = '#{base_class.name}'"
|
||||
end
|
||||
|
||||
case reflection.options[:dependent]
|
||||
when :destroy, true
|
||||
module_eval "before_destroy '#{reflection.name}.each { |o| o.destroy }'"
|
||||
when :delete_all
|
||||
module_eval "before_destroy { |record| #{reflection.class_name}.delete_all(%(#{reflection.primary_key_name} = \#{record.quoted_id})) }"
|
||||
module_eval "before_destroy { |record| #{reflection.class_name}.delete_all(%(#{dependent_conditions})) }"
|
||||
when :nullify
|
||||
module_eval "before_destroy { |record| #{reflection.class_name}.update_all(%(#{reflection.primary_key_name} = NULL), %(#{reflection.primary_key_name} = \#{record.quoted_id})) }"
|
||||
module_eval "before_destroy { |record| #{reflection.class_name}.update_all(%(#{reflection.primary_key_name} = NULL), %(#{dependent_conditions})) }"
|
||||
when nil, false
|
||||
# pass
|
||||
else
|
||||
|
|
|
@ -118,10 +118,11 @@ module ActiveRecord
|
|||
|
||||
def primary_key_name
|
||||
return @primary_key_name if @primary_key_name
|
||||
|
||||
case macro
|
||||
when :belongs_to
|
||||
case
|
||||
when macro == :belongs_to
|
||||
@primary_key_name = options[:foreign_key] || class_name.foreign_key
|
||||
when options[:as]
|
||||
@primary_key_name = options[:foreign_key] || "#{options[:as]}_id"
|
||||
else
|
||||
@primary_key_name = options[:foreign_key] || active_record.name.foreign_key
|
||||
end
|
||||
|
|
|
@ -69,13 +69,72 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_create_polymorphic_has_many_with_scope
|
||||
tagging = posts(:welcome).taggings.create(:tag => tags(:general))
|
||||
old_count = posts(:welcome).taggings.count
|
||||
tagging = posts(:welcome).taggings.create(:tag => tags(:misc))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
assert_equal old_count+1, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_create_polymorphic_has_one_with_scope
|
||||
tagging = posts(:welcome).tagging.create(:tag => tags(:general))
|
||||
old_count = Tagging.count
|
||||
tagging = posts(:welcome).tagging.create(:tag => tags(:misc))
|
||||
assert_equal "Post", tagging.taggable_type
|
||||
assert_equal old_count+1, Tagging.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_delete_all
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDeleteAll'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :delete_all)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_destroy
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyDestroy'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :destroy)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_many_with_nullify
|
||||
assert_equal 1, posts(:welcome).taggings.count
|
||||
posts(:welcome).taggings.first.update_attribute :taggable_type, 'PostWithHasManyNullify'
|
||||
post = find_post_with_dependency(1, :has_many, :taggings, :nullify)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count, Tagging.count
|
||||
assert_equal 0, posts(:welcome).taggings.count
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_one_with_destroy
|
||||
assert posts(:welcome).tagging
|
||||
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneDestroy'
|
||||
post = find_post_with_dependency(1, :has_one, :tagging, :destroy)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count-1, Tagging.count
|
||||
assert_nil posts(:welcome).tagging(true)
|
||||
end
|
||||
|
||||
def test_delete_polymorphic_has_one_with_nullify
|
||||
assert posts(:welcome).tagging
|
||||
posts(:welcome).tagging.update_attribute :taggable_type, 'PostWithHasOneNullify'
|
||||
post = find_post_with_dependency(1, :has_one, :tagging, :nullify)
|
||||
|
||||
old_count = Tagging.count
|
||||
post.destroy
|
||||
assert_equal old_count, Tagging.count
|
||||
assert_nil posts(:welcome).tagging(true)
|
||||
end
|
||||
|
||||
def test_has_many_with_piggyback
|
||||
|
@ -139,4 +198,15 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|||
tagging.destroy
|
||||
assert posts(:welcome, :reload)[:taggings_count].zero?
|
||||
end
|
||||
|
||||
private
|
||||
# create dynamic Post models to allow different dependency options
|
||||
def find_post_with_dependency(post_id, association, association_name, dependency)
|
||||
class_name = "PostWith#{association.to_s.classify}#{dependency.to_s.classify}"
|
||||
Post.find(post_id).update_attribute :type, class_name
|
||||
klass = Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
||||
klass.set_table_name 'posts'
|
||||
klass.send(association, association_name, :as => :taggable, :dependent => dependency)
|
||||
klass.find(post_id)
|
||||
end
|
||||
end
|
||||
|
|
2
activerecord/test/fixtures/post.rb
vendored
2
activerecord/test/fixtures/post.rb
vendored
|
@ -18,7 +18,7 @@ class Post < ActiveRecord::Base
|
|||
has_many :special_comments
|
||||
|
||||
has_and_belongs_to_many :categories
|
||||
has_and_belongs_to_many :special_categories, :join_table => "categories_posts"
|
||||
has_and_belongs_to_many :special_categories, :join_table => "categories_posts", :association_foreign_key => 'category_id'
|
||||
|
||||
has_many :taggings, :as => :taggable
|
||||
has_many :tags, :through => :taggings
|
||||
|
|
6
activerecord/test/fixtures/taggings.yml
vendored
6
activerecord/test/fixtures/taggings.yml
vendored
|
@ -9,3 +9,9 @@ thinking_general:
|
|||
tag_id: 1
|
||||
taggable_id: 2
|
||||
taggable_type: Post
|
||||
|
||||
fake:
|
||||
id: 3
|
||||
tag_id: 1
|
||||
taggable_id: 1
|
||||
taggable_type: FakeModel
|
Loading…
Reference in a new issue