Spec-Zone.ru › Ruby on Rails 8.1

module 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 продолжит правильно определять имя таблицы.

base_class [R]

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

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

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

ApplicationRecord.base_class # => ApplicationRecord
Shape.base_class # => Shape
Polygon.base_class # => Polygon
Square.base_class # => Polygon

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

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

Возвращает значение, указывающее, является ли этот класс абстрактным.

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

Возвращает значение, указывающее, является ли класс базовым. Подробнее см. base_class.

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

new (attributes = nil, &block) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 56
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 218
def polymorphic_class_for(name)
  if store_full_class_name
    name.constantize
  else
    compute_type(name)
  end
end

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

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

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

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

primary_abstract_class () Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 177
def primary_abstract_class
  if ActiveRecord.application_record_class && ActiveRecord.application_record_class.name != name
    raise ArgumentError, "The `primary_abstract_class` is already set to #{ActiveRecord.application_record_class.inspect}. There can only be one `primary_abstract_class` in an application."
  end

  self.abstract_class = true
  ActiveRecord.application_record_class = self
end

Задаёт класс записи приложения для Active Record.

Это полезно, если в вашем приложении вместо ApplicationRecord в качестве основного абстрактного класса используется другой класс. Этот класс будет использовать то же подключение к базе данных, что и Active Record. Именно этот класс подключается к вашей основной базе данных.

sti_class_for (type_name) Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 194
def sti_class_for(type_name)
  if store_full_sti_class && store_full_class_name
    type_name.constantize
  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. " \
    "If you wish to disable single-table inheritance for #{name} set " \
    "#{name}.inheritance_column to nil"
end

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

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

sti_name () Показать исходный код
# File activerecord/lib/active_record/inheritance.rb, line 187
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 242
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.
    type_name.constantize
  else
    type_candidate = @_type_candidates_cache[type_name]
    if type_candidate && type_constant = type_candidate.safe_constantize
      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 = candidate.safe_constantize
      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–2021 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

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