module ActiveRecord::Inheritance::ClassMethods
Attributes
Set this to true if this is an abstract class (see
abstract_class?
).
Public Instance Methods
Returns whether this class is an abstract class or not.
# File lib/active_record/inheritance.rb, line 50 def abstract_class? defined?(@abstract_class) && @abstract_class == true 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 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.
# File lib/active_record/inheritance.rb, line 42 def base_class class_of_active_record_descendant(self) end
True if this isn't a concrete subclass needing a STI type condition.
# File lib/active_record/inheritance.rb, line 15 def descends_from_active_record? if superclass.abstract_class? superclass.descends_from_active_record? else superclass == Base || !columns_hash.include?(inheritance_column) end end
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.
# File lib/active_record/inheritance.rb, line 61 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 instance = use_identity_map(sti_class, record_id, record) else instance = sti_class.allocate.init_with('attributes' => record) end instance end
# File lib/active_record/inheritance.rb, line 54 def sti_name store_full_sti_class ? name : name.demodulize end
# File lib/active_record/inheritance.rb, line 28 def symbolized_base_class @symbolized_base_class ||= base_class.to_s.to_sym end
# File lib/active_record/inheritance.rb, line 32 def symbolized_sti_name @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class end
Protected Instance Methods
Returns the class descending directly from ActiveRecord::Base or an abstract class, if any, in the inheritance hierarchy.
# File lib/active_record/inheritance.rb, line 78 def class_of_active_record_descendant(klass) if klass == Base || klass.superclass == Base || klass.superclass.abstract_class? klass elsif klass.superclass.nil? raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord" else class_of_active_record_descendant(klass.superclass) 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.
# File lib/active_record/inheritance.rb, line 90 def compute_type(type_name) if type_name.match(/^::/) # If the type is prefixed with a scope operator then we assume that # the type_name is an absolute reference. ActiveSupport::Dependencies.constantize(type_name) else # Build a list of candidates to search for candidates = [] name.scan(/::|$/) { candidates.unshift "#{$`}::#{type_name}" } candidates << type_name candidates.each do |candidate| begin constant = ActiveSupport::Dependencies.constantize(candidate) return constant if candidate == constant.to_s rescue NameError => e # We don't want to swallow NoMethodError < NameError errors raise e unless e.instance_of?(NameError) end end raise NameError, "uninitialized constant #{candidates.first}" end end
Private Instance Methods
# File lib/active_record/inheritance.rb, line 132 def find_sti_class(type_name) if type_name.blank? || !columns_hash.include?(inheritance_column) self else begin if store_full_sti_class ActiveSupport::Dependencies.constantize(type_name) else compute_type(type_name) end rescue NameError raise SubclassNotFound, "The single-table inheritance mechanism failed to locate the subclass: '#{type_name}'. " + "This error is raised because the column '#{inheritance_column}' is reserved for storing the class in case of inheritance. " + "Please rename this column if you didn't intend it to be used for storing the inheritance class " + "or overwrite #{name}.inheritance_column to use another column for that information." end end end
# File lib/active_record/inheritance.rb, line 152 def type_condition(table = arel_table) sti_column = table[inheritance_column.to_sym] sti_names = ([self] + descendants).map { |model| model.sti_name } sti_column.in(sti_names) end
# File lib/active_record/inheritance.rb, line 117 def use_identity_map(sti_class, record_id, record) 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 instance end