跳至内容 跳至搜索
方法
A
B
C
D
N
P
S

属性

[RW] abstract_class

如果这是一个抽象类,则将其设置为 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 将继续正确派生表名。

[R] base_class

返回继承层次结构中第一个从抽象类或 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?()

返回此类是否为基类。有关更多信息,请参见 base_class

# File activerecord/lib/active_record/inheritance.rb, line 119
def base_class?
  base_class == self
end

descends_from_active_record?()

如果不需要 STI 类型条件,则返回 true。如果需要应用 STI 类型条件,则返回 false

# 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

new(attributes = nil, &block)

确定传递的属性之一是否为继承列,如果继承列是 attr 可访问的,则它会初始化给定子类的实例,而不是基类的实例。

# 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)

返回给定 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

polymorphic_name()

返回要存储在多态类型列中的值,用于多态 Associations

# File activerecord/lib/active_record/inheritance.rb, line 211
def polymorphic_name
  store_full_class_name ? base_class.name : base_class.name.demodulize
end

primary_abstract_class()

为 Active Record 设置应用程序记录类

如果您在应用程序中使用与 ApplicationRecord 不同的类作为您的主要抽象类,这将很有用。此类将与 Active Record 共享数据库连接。它是连接到您的主数据库的类。

# 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

sti_class_for(type_name)

返回给定 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

sti_name()

返回要存储在 STI 继承列中的值。

# File activerecord/lib/active_record/inheritance.rb, line 187
def sti_name
  store_full_sti_class && store_full_class_name ? name : name.demodulize
end

实例受保护方法

compute_type(type_name)

使用当前模块作为前缀返回记录的类类型。因此,MyApp::Business::Account 的后代将显示为 MyApp::Business::AccountSubclass。

# 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