diff options
Diffstat (limited to 'activerecord/lib/active_record/inheritance.rb')
-rw-r--r-- | activerecord/lib/active_record/inheritance.rb | 79 |
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) |