diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 79faa9326d..e0ce0af9d6 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,13 @@ +* Use the default inheritance `:type` when instantiating a new object. + + Example: + + # In the schema, BaseModel specifies 'SubType' as the default `:type` value + subtype = BaseModel.new + assert_equals SubType, subtype.class + + *Kuldeep Aggarwal* + * Fix `rake db:structure:dump` on Postgres when multiple schemas are used. Fixes #22346. diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb index 8b719e0bcb..ed95b30f80 100644 --- a/activerecord/lib/active_record/inheritance.rb +++ b/activerecord/lib/active_record/inheritance.rb @@ -55,6 +55,8 @@ module ActiveRecord subclass = subclass_from_attributes(attrs) end + subclass ||= subclass_from_defaults + if subclass && subclass != self subclass.new(*args, &block) else @@ -201,6 +203,16 @@ module ActiveRecord attribute_names.include?(inheritance_column) && (attrs.is_a?(Hash) || attrs.respond_to?(:permitted?)) end + def subclass_from_defaults? + attribute_names.include?(inheritance_column) && columns_hash[inheritance_column].try(:default) + end + + def subclass_from_defaults + if subclass_from_defaults? + find_sti_class(columns_hash[inheritance_column].default) + end + end + def subclass_from_attributes(attrs) attrs = attrs.to_h if attrs.respond_to?(:permitted?) subclass_name = attrs.with_indifferent_access[inheritance_column] diff --git a/activerecord/test/cases/inheritance_test.rb b/activerecord/test/cases/inheritance_test.rb index 52e3734dd0..e7709c04c8 100644 --- a/activerecord/test/cases/inheritance_test.rb +++ b/activerecord/test/cases/inheritance_test.rb @@ -478,4 +478,24 @@ class InheritanceComputeTypeTest < ActiveRecord::TestCase product = Shop::Product.new(:type => phone) assert product.save end + + def test_inheritance_new_with_subclass_as_default + original_type = Company.columns_hash["type"].default + ActiveRecord::Base.connection.change_column_default :companies, :type, 'Firm' + Company.reset_column_information + # this is the case when attrs is a +Hash+, but we didn't specify the type, + # so we need default type. + firm = Company.new(firm_name: 'Shri Hans Plastic') + assert_equal 'Firm', firm.type + assert_instance_of Firm, firm + firm = Company.new # this is the case when attrs is nil + assert_equal 'Firm', firm.type + assert_instance_of Firm, firm + firm = Company.new(type: 'Client') + assert_equal 'Client', firm.type + assert_instance_of Client, firm + ensure + ActiveRecord::Base.connection.change_column_default :companies, :type, original_type + Company.reset_column_information + end end