aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/inheritance.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/inheritance.rb')
-rw-r--r--activerecord/lib/active_record/inheritance.rb79
1 files changed, 39 insertions, 40 deletions
diff --git a/activerecord/lib/active_record/inheritance.rb b/activerecord/lib/active_record/inheritance.rb
index eaa7deac5a..04fff99a6e 100644
--- a/activerecord/lib/active_record/inheritance.rb
+++ b/activerecord/lib/active_record/inheritance.rb
@@ -1,13 +1,16 @@
-require 'active_support/concern'
module ActiveRecord
+ ActiveSupport.on_load(:active_record_config) do
+ # Determine whether to store the full constant name including namespace when using STI
+ mattr_accessor :store_full_sti_class, instance_accessor: false
+ self.store_full_sti_class = true
+ end
+
module Inheritance
extend ActiveSupport::Concern
included do
- # Determine whether to store the full constant name including namespace when using STI
config_attribute :store_full_sti_class
- self.store_full_sti_class = true
end
module ClassMethods
@@ -37,17 +40,43 @@ module ActiveRecord
@symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
end
- # Returns the base AR subclass that this class descends from. If A
- # extends AR::Base, A.base_class will return A. If B descends from A
+ # Returns the class descending directly from ActiveRecord::Base (or
+ # that includes ActiveRecord::Model), or an abstract class, if any, in
+ # the inheritance hierarchy.
+ #
+ # If A extends AR::Base, A.base_class will return A. If B descends from A
# through some arbitrarily deep hierarchy, B.base_class will return A.
#
# If B < A and C < B and if A is an abstract_class then both B.base_class
# and C.base_class would return B as the answer since A is an abstract_class.
def base_class
- class_of_active_record_descendant(self)
+ unless self < Model::Tag
+ raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
+ end
+
+ sup = active_record_super
+ if sup == Base || sup == Model || sup.abstract_class?
+ self
+ else
+ sup.base_class
+ end
end
# Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
+ # If you are using inheritance with ActiveRecord and don't want child classes
+ # to utilize the implied STI table name of the parent class, this will need to be true.
+ # For example, given the following:
+ #
+ # class SuperClass < ActiveRecord::Base
+ # self.abstract_class = true
+ # end
+ # class Child < SuperClass
+ # self.table_name = 'the_table_i_really_want'
+ # end
+ #
+ #
+ # <tt>self.abstract_class = true</tt> is required to make <tt>Child<.find,.create, or any Arel method></tt> use <tt>the_table_i_really_want</tt> instead of a table called <tt>super_classes</tt>
+ #
attr_accessor :abstract_class
# Returns whether this class is an abstract class or not.
@@ -62,25 +91,10 @@ module ActiveRecord
# Finder methods must instantiate through this method to work with the
# single-table inheritance model that makes it possible to create
# objects of different types from the same table.
- def instantiate(record)
- sti_class = find_sti_class(record[inheritance_column])
- record_id = sti_class.primary_key && record[sti_class.primary_key]
-
- if ActiveRecord::IdentityMap.enabled? && record_id
- if (column = sti_class.columns_hash[sti_class.primary_key]) && column.number?
- record_id = record_id.to_i
- end
- if instance = IdentityMap.get(sti_class, record_id)
- instance.reinit_with('attributes' => record)
- else
- instance = sti_class.allocate.init_with('attributes' => record)
- IdentityMap.add(instance)
- end
- else
- instance = sti_class.allocate.init_with('attributes' => record)
- end
-
- instance
+ def instantiate(record, column_types = {})
+ sti_class = find_sti_class(record[inheritance_column])
+ column_types = sti_class.decorate_columns(column_types)
+ sti_class.allocate.init_with('attributes' => record, 'column_types' => column_types)
end
# For internal use.
@@ -93,21 +107,6 @@ module ActiveRecord
protected
- # Returns the class descending directly from ActiveRecord::Base or an
- # abstract class, if any, in the inheritance hierarchy.
- def class_of_active_record_descendant(klass)
- unless klass < Model
- raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
- end
-
- sup = klass.active_record_super
- if [Base, Model].include?(klass) || [Base, Model].include?(sup) || sup.abstract_class?
- klass
- else
- class_of_active_record_descendant(sup)
- end
- end
-
# Returns the class type of the record using the current module as a prefix. So descendants of
# MyApp::Business::Account would appear as MyApp::Business::AccountSubclass.
def compute_type(type_name)