module ActiveRecord::Inheritance::ClassMethods
Краткое описание полей
Установите это в 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 будет продолжать правильно выводить имя таблицы.
Возвращает класс, непосредственно наследуемый от 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 является абстрактным классом.
Открытые методы экземпляра
# File activerecord/lib/active_record/inheritance.rb, line 156 def abstract_class? defined?(@abstract_class) && @abstract_class == true end
Возвращает, является ли этот класс абстрактным или нет.
# File activerecord/lib/active_record/inheritance.rb, line 108 def base_class? base_class == self end
Возвращает, является ли класс базовым. См. base_class для получения дополнительной информации.
# File activerecord/lib/active_record/inheritance.rb, line 81
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.
# File activerecord/lib/active_record/inheritance.rb, line 213 def inherited(subclass) subclass.set_base_class subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new) super end
# File activerecord/lib/active_record/inheritance.rb, line 55
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 Определяет, является ли один из переданных атрибутов столбцом наследования, и если столбец наследования является доступным атрибутом, он инициализирует экземпляр заданного подкласса вместо базового класса.
# File activerecord/lib/active_record/inheritance.rb, line 205
def polymorphic_class_for(name)
if store_full_class_name
name.constantize
else
compute_type(name)
end
end Возвращает класс для предоставленного name.
Он используется для поиска класса, соответствующего значению, хранящемуся в столбце полиморфного типа.
# File activerecord/lib/active_record/inheritance.rb, line 198 def polymorphic_name store_full_class_name ? base_class.name : base_class.name.demodulize end
Возвращает значение, которое должно храниться в столбце полиморфного типа для полиморфного Associations.
# File activerecord/lib/active_record/inheritance.rb, line 166
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. Это класс, который подключается к вашей основной базе данных.
# File activerecord/lib/active_record/inheritance.rb, line 183
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."
end Возвращает класс для предоставленного type_name.
Он используется для поиска класса, соответствующего значению, хранящемуся в столбце наследования.
# File activerecord/lib/active_record/inheritance.rb, line 176 def sti_name store_full_sti_class && store_full_class_name ? name : name.demodulize end
Возвращает значение, которое должно храниться в столбце наследования для STI.
Защищенные методы экземпляра
# File activerecord/lib/active_record/inheritance.rb, line 235
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.