1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Support storing demodulized class name for polymorphic type

This is an alternative of #29722.

Before Rails 6.1, storing demodulized class name is supported only for
STI type by `store_full_sti_class` class attribute.

Now `store_full_class_name` class attribute can handle both STI and
polymorphic types.

Closes #29722.

See also #29601, #32048, #32148.
This commit is contained in:
Ryuta Kamizono 2020-06-21 11:42:56 +09:00
parent 97066dac7a
commit 62cfbdf36e
3 changed files with 100 additions and 17 deletions

View file

@ -1,3 +1,12 @@
* Support storing demodulized class name for polymorphic type.
Before Rails 6.1, storing demodulized class name is supported only for STI type
by `store_full_sti_class` class attribute.
Now `store_full_class_name` class attribute can handle both STI and polymorphic types.
*Ryuta Kamizono*
* Deprecate `rails db:structure:{load, dump}` tasks and extend
`rails db:schema:{load, dump}` tasks to work with either `:ruby` or `:sql` format,
depending on `config.active_record.schema_format` configuration value.

View file

@ -38,6 +38,8 @@ module ActiveRecord
extend ActiveSupport::Concern
included do
class_attribute :store_full_class_name, instance_writer: false, default: true
# Determines whether to store the full constant name including namespace when using STI.
# This is true, by default.
class_attribute :store_full_sti_class, instance_writer: false, default: true
@ -164,14 +166,14 @@ module ActiveRecord
# Returns the value to be stored in the inheritance column for STI.
def sti_name
store_full_sti_class ? name : name.demodulize
store_full_sti_class && store_full_class_name ? name : name.demodulize
end
# Returns the class for the provided +type_name+.
#
# It is used to find the class correspondent to the value stored in the inheritance column.
def sti_class_for(type_name)
if store_full_sti_class
if store_full_sti_class && store_full_class_name
ActiveSupport::Dependencies.constantize(type_name)
else
compute_type(type_name)
@ -186,14 +188,18 @@ module ActiveRecord
# Returns the value to be stored in the polymorphic type column for Polymorphic Associations.
def polymorphic_name
base_class.name
store_full_class_name ? base_class.name : base_class.name.demodulize
end
# Returns the class for the provided +name+.
#
# It is used to find the class correspondent to the value stored in the polymorphic type column.
def polymorphic_class_for(name)
name.constantize
if store_full_class_name
ActiveSupport::Dependencies.constantize(name)
else
compute_type(name)
end
end
def inherited(subclass)

View file

@ -8,14 +8,10 @@ module Namespaced
class Post < ActiveRecord::Base
self.table_name = "posts"
has_one :tagging, as: :taggable, class_name: "Tagging"
def self.polymorphic_name
sti_name
end
end
end
module PolymorphicFullStiClassNamesSharedTest
module FullStiClassNamesSharedTest
def setup
@old_store_full_sti_class = ActiveRecord::Base.store_full_sti_class
ActiveRecord::Base.store_full_sti_class = store_full_sti_class
@ -31,7 +27,7 @@ module PolymorphicFullStiClassNamesSharedTest
def test_class_names
ActiveRecord::Base.store_full_sti_class = !store_full_sti_class
post = Namespaced::Post.find_by_title("Great stuff")
assert_nil post.tagging
assert_equal @tagging, post.tagging
ActiveRecord::Base.store_full_sti_class = store_full_sti_class
post = Namespaced::Post.find_by_title("Great stuff")
@ -41,7 +37,7 @@ module PolymorphicFullStiClassNamesSharedTest
def test_class_names_with_includes
ActiveRecord::Base.store_full_sti_class = !store_full_sti_class
post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff")
assert_nil post.tagging
assert_equal @tagging, post.tagging
ActiveRecord::Base.store_full_sti_class = store_full_sti_class
post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff")
@ -51,7 +47,7 @@ module PolymorphicFullStiClassNamesSharedTest
def test_class_names_with_eager_load
ActiveRecord::Base.store_full_sti_class = !store_full_sti_class
post = Namespaced::Post.eager_load(:tagging).find_by_title("Great stuff")
assert_nil post.tagging
assert_equal @tagging, post.tagging
ActiveRecord::Base.store_full_sti_class = store_full_sti_class
post = Namespaced::Post.eager_load(:tagging).find_by_title("Great stuff")
@ -62,15 +58,15 @@ module PolymorphicFullStiClassNamesSharedTest
post = Namespaced::Post.find_by_title("Great stuff")
ActiveRecord::Base.store_full_sti_class = !store_full_sti_class
assert_nil Tagging.find_by(taggable: post)
assert_equal @tagging, Tagging.find_by(taggable: post)
ActiveRecord::Base.store_full_sti_class = store_full_sti_class
assert_equal @tagging, Tagging.find_by(taggable: post)
end
end
class PolymorphicFullStiClassNamesTest < ActiveRecord::TestCase
include PolymorphicFullStiClassNamesSharedTest
class FullStiClassNamesTest < ActiveRecord::TestCase
include FullStiClassNamesSharedTest
private
def store_full_sti_class
@ -78,11 +74,83 @@ class PolymorphicFullStiClassNamesTest < ActiveRecord::TestCase
end
end
class PolymorphicNonFullStiClassNamesTest < ActiveRecord::TestCase
include PolymorphicFullStiClassNamesSharedTest
class NonFullStiClassNamesTest < ActiveRecord::TestCase
include FullStiClassNamesSharedTest
private
def store_full_sti_class
false
end
end
module PolymorphicFullClassNamesSharedTest
def setup
@old_store_full_class_name = ActiveRecord::Base.store_full_class_name
ActiveRecord::Base.store_full_class_name = store_full_class_name
post = Namespaced::Post.create(title: "Great stuff", body: "This is not", author_id: 1)
@tagging = post.create_tagging!
end
def teardown
ActiveRecord::Base.store_full_class_name = @old_store_full_class_name
end
def test_class_names
ActiveRecord::Base.store_full_class_name = !store_full_class_name
post = Namespaced::Post.find_by_title("Great stuff")
assert_nil post.tagging
ActiveRecord::Base.store_full_class_name = store_full_class_name
post = Namespaced::Post.find_by_title("Great stuff")
assert_equal @tagging, post.tagging
end
def test_class_names_with_includes
ActiveRecord::Base.store_full_class_name = !store_full_class_name
post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff")
assert_nil post.tagging
ActiveRecord::Base.store_full_class_name = store_full_class_name
post = Namespaced::Post.includes(:tagging).find_by_title("Great stuff")
assert_equal @tagging, post.tagging
end
def test_class_names_with_eager_load
ActiveRecord::Base.store_full_class_name = !store_full_class_name
post = Namespaced::Post.eager_load(:tagging).find_by_title("Great stuff")
assert_nil post.tagging
ActiveRecord::Base.store_full_class_name = store_full_class_name
post = Namespaced::Post.eager_load(:tagging).find_by_title("Great stuff")
assert_equal @tagging, post.tagging
end
def test_class_names_with_find_by
post = Namespaced::Post.find_by_title("Great stuff")
ActiveRecord::Base.store_full_class_name = !store_full_class_name
assert_nil Tagging.find_by(taggable: post)
ActiveRecord::Base.store_full_class_name = store_full_class_name
assert_equal @tagging, Tagging.find_by(taggable: post)
end
end
class PolymorphicFullClassNamesTest < ActiveRecord::TestCase
include PolymorphicFullClassNamesSharedTest
private
def store_full_class_name
true
end
end
class PolymorphicNonFullClassNamesTest < ActiveRecord::TestCase
include PolymorphicFullClassNamesSharedTest
private
def store_full_class_name
false
end
end