Spec-Zone.ru › Ruby on Rails 6.1

модуль ActiveRecord::Inheritance::ClassMethods

Атрибуты

abstract_class[RW]

Установите это значение в true, если это абстрактный класс (см. abstract_class?). Если вы используете наследование с Active Record и не хотите, чтобы класс считался частью иерархии STI, вы должны установить это значение в true. ApplicationRecord, например, генерируется как абстрактный класс.

Рассмотрите следующие значения по умолчанию:

Shape = Class.new(ActiveRecord::Base)
Polygon = Class.new(Shape)
Square = Class.new(Polygon)

Shape.table_name   # => "shapes"
Polygon.table_name # => "shapes"
Square.table_name  # => "shapes"
Shape.create!      # => #<Shape id: 1, type: nil>
Polygon.create!    # => #<Polygon id: 2, type: "Polygon">
Square.create!     # => #<Square id: 3, type: "Square">

Однако, при использовании abstract_class, Shape исключается из иерархии:

class Shape < ActiveRecord::Base
  self.abstract_class = true
end
Polygon = Class.new(Shape)
Square = Class.new(Polygon)

Shape.table_name   # => nil
Polygon.table_name # => "polygons"
Square.table_name  # => "polygons"
Shape.create!      # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
Polygon.create!    # => #<Polygon id: 1, type: nil>
Square.create!     # => #<Square id: 2, type: "Square">

Обратите внимание, что в приведенном выше примере, чтобы запретить создание простого Polygon, вы должны использовать validates :type, presence: true, а не устанавливать его как абстрактный класс. Таким образом, Polygon останется в иерархии, и Active Record продолжит правильно выводить имя таблицы.

Открытые методы экземпляра

abstract_class?() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 163
def abstract_class?
  defined?(@abstract_class) && @abstract_class == true
end

Возвращает, является ли данный класс абстрактным классом или нет.

base_class() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 101
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

Возвращает класс, непосредственно наследуемый от ActiveRecord::Base, или абстрактный класс, если таковой имеется, в иерархии наследования.

Если A наследуется от ActiveRecord::Base, A.base_class вернёт A. Если B наследуется от A через произвольную глубокую иерархию, B.base_class вернёт A.

Если B < A и C < B, и если A является abstract_class, то и B.base_class, и C.base_class вернут B, так как A является абстрактным классом.

base_class?() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 115
def base_class?
  base_class == self
end

Возвращает, является ли класс базовым классом. Смотрите base_class для получения дополнительной информации.

descends_from_active_record?() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 78
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

Возвращает true, если условие типа STI не требуется. Возвращает false, если условие типа STI необходимо применить.

inherited(subclass) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 205
def inherited(subclass)
  subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
  super
end
Вызывает метод суперкласса
new(attributes = nil, &block) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 52
def new(attributes = nil, &block)
  if abstract_class? || self == Base
    raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
  end

  if _has_attribute?(inheritance_column)
    subclass = subclass_from_attributes(attributes)

    if subclass.nil? && scope_attributes = current_scope&.scope_for_create
      subclass = subclass_from_attributes(scope_attributes)
    end

    if subclass.nil? && base_class?
      subclass = subclass_from_attributes(column_defaults)
    end
  end

  if subclass && subclass != self
    subclass.new(attributes, &block)
  else
    super
  end
end

Определяет, является ли один из переданных атрибутов столбцом наследования, и если столбец наследования доступен по атрибуту, инициализирует экземпляр заданного подкласса вместо базового класса.

Вызывает метод суперкласса
polymorphic_class_for(name) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 197
def polymorphic_class_for(name)
  if store_full_class_name
    ActiveSupport::Dependencies.constantize(name)
  else
    compute_type(name)
  end
end

Возвращает класс для предоставленного name.

Используется для поиска класса, соответствующего значению, хранящемуся в столбце типа полиморфизма.

polymorphic_name() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 190
def polymorphic_name
  store_full_class_name ? base_class.name : base_class.name.demodulize
end

Возвращает значение, которое должно храниться в столбце типа полиморфизма для полиморфного Associations.

sti_class_for(type_name) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 175
def sti_class_for(type_name)
  if store_full_sti_class && store_full_class_name
    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

Возвращает класс для предоставленного type_name.

Используется для поиска класса, соответствующего значению, хранящемуся в столбце наследования.

sti_name() Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 168
def sti_name
  store_full_sti_class && store_full_class_name ? name : name.demodulize
end

Возвращает значение, которое должно храниться в столбце наследования для STI.

Защищенные методы экземпляра

compute_type(type_name) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 213
def compute_type(type_name)
  if type_name.start_with?("::")
    # 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
    type_candidate = @_type_candidates_cache[type_name]
    if type_candidate && type_constant = ActiveSupport::Dependencies.safe_constantize(type_candidate)
      return type_constant
    end

    # 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)
      if candidate == constant.to_s
        @_type_candidates_cache[type_name] = candidate
        return constant
      end
    end

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

Возвращает тип класса записи, используя текущий модуль в качестве префикса. Таким образом, потомки MyApp::Business::Account будут отображаться как MyApp::Business::AccountSubclass.

© 2004–2020 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API