module ActiveRecord::Inheritance::ClassMethods - activerecord-4.2.3 Documentation

# module ActiveRecord::Inheritance::ClassMethods

### Attributes

abstract_class[RW]

Set this to true if this is an abstract class (see `abstract_class?`). 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

`self.abstract_class = true` is required to make `Child<.find,.create, or any Arel method>` use `the_table_i_really_want` instead of a table called `super_classes`

### Public Instance Methods

abstract_class?() click to toggle source

Returns whether this class is an abstract class or not.

    # File lib/active_record/inheritance.rb, line 130
    def abstract_class?
      defined?(@abstract_class) && @abstract_class == true
    end

base_class() click to toggle source

Returns the class descending directly from ActiveRecord::Base, 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.

    # File lib/active_record/inheritance.rb, line 100
    def base_class
      unless self < Base
        raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
      end

      if superclass == Base || superclass.abstract_class?
        self
      else
        superclass.base_class
      end
    end

descends_from_active_record?() click to toggle source

Returns `true` if this does not need STI type condition. Returns `false` if STI type condition needs to be applied.

    # File lib/active_record/inheritance.rb, line 67
    def descends_from_active_record?
      if self == Base
        false
      elsif superclass.abstract_class?
        superclass.descends_from_active_record?
      else
        superclass == Base || !columns_hash.include?(inheritance_column)
      end
    end

new(*args, &block) click to toggle source

Determines if one of the attributes passed in is the inheritance column, and if the inheritance column is attr accessible, it initializes an instance of the given subclass instead of the base class.

Calls superclass method

    # File lib/active_record/inheritance.rb, line 48
    def new(*args, &block)
      if abstract_class? || self == Base
        raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
      end

      attrs = args.first
      if subclass_from_attributes?(attrs)
        subclass = subclass_from_attributes(attrs)
      end

      if subclass
        subclass.new(*args, &block)
      else
        super
      end
    end

sti_name() click to toggle source

    # File lib/active_record/inheritance.rb, line 134
    def sti_name
      store_full_sti_class ? name : name.demodulize
    end

symbolized_base_class() click to toggle source

    # File lib/active_record/inheritance.rb, line 82
    def symbolized_base_class
      ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_base_class` is deprecated and will be removed without replacement.')
      @symbolized_base_class ||= base_class.to_s.to_sym
    end

symbolized_sti_name() click to toggle source

    # File lib/active_record/inheritance.rb, line 87
    def symbolized_sti_name
      ActiveSupport::Deprecation.warn('`ActiveRecord::Base.symbolized_sti_name` is deprecated and will be removed without replacement.')
      @symbolized_sti_name ||= sti_name.present? ? sti_name.to_sym : symbolized_base_class
    end

### Protected Instance Methods

compute_type(type_name) click to toggle source

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 142
    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|
          constant = ActiveSupport::Dependencies.safe_constantize(candidate)
          return constant if candidate == constant.to_s
        end

        raise NameError.new("uninitialized constant #{candidates.first}", candidates.first)
      end
    end

### Private Instance Methods

discriminate_class_for_record(record) click to toggle source

Called by `instantiate` to decide which class to use for a new record instance. For single-table inheritance, we check the record for a `type` column and return the corresponding class.

Calls superclass method

    # File lib/active_record/inheritance.rb, line 167
    def discriminate_class_for_record(record)
      if using_single_table_inheritance?(record)
        find_sti_class(record[inheritance_column])
      else
        super
      end
    end

find_sti_class(type_name) click to toggle source

    # File lib/active_record/inheritance.rb, line 179
    def find_sti_class(type_name)
      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

subclass_from_attributes(attrs) click to toggle source

    # File lib/active_record/inheritance.rb, line 208
    def subclass_from_attributes(attrs)
      subclass_name = attrs.with_indifferent_access[inheritance_column]

      if subclass_name.present? && subclass_name != self.name
        subclass = subclass_name.safe_constantize

        unless descendants.include?(subclass)
          raise ActiveRecord::SubclassNotFound.new("Invalid single-table inheritance type: #{subclass_name} is not a subclass of #{name}")
        end

        subclass
      end
    end

subclass_from_attributes?(attrs) click to toggle source

Detect the subclass from the inheritance column of attrs. If the inheritance column value is not self or a valid subclass, raises ActiveRecord::SubclassNotFound If this is a StrongParameters hash, and access to inheritance_column is not permitted, this will ignore the inheritance column and return nil

    # File lib/active_record/inheritance.rb, line 204
    def subclass_from_attributes?(attrs)
      columns_hash.include?(inheritance_column) && attrs.is_a?(Hash)
    end

type_condition(table = arel_table) click to toggle source

    # File lib/active_record/inheritance.rb, line 193
    def type_condition(table = arel_table)
      sti_column = table[inheritance_column]
      sti_names  = ([self] + descendants).map { |model| model.sti_name }

      sti_column.in(sti_names)
    end

using_single_table_inheritance?(record) click to toggle source

    # File lib/active_record/inheritance.rb, line 175
    def using_single_table_inheritance?(record)
      record[inheritance_column].present? && columns_hash.include?(inheritance_column)
    end