跳至内容 跳至搜索
方法
C
I
N
P
Q
R
S
T

实例公共方法

column_defaults()

返回一个哈希,其中键是列名,值为对此表实例化 Active Record 对象时的默认值。

# File activerecord/lib/active_record/model_schema.rb, line 493
def column_defaults
  load_schema
  @column_defaults ||= _default_attributes.deep_dup.to_hash.freeze
end

column_for_attribute(name)

返回指定属性的列对象。如果指定属性不存在,则返回 ActiveRecord::ConnectionAdapters::NullColumn。

class Person < ActiveRecord::Base
end

person = Person.new
person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
# => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>

person.column_for_attribute(:nothing)
# => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
# File activerecord/lib/active_record/model_schema.rb, line 484
def column_for_attribute(name)
  name = name.to_s
  columns_hash.fetch(name) do
    ConnectionAdapters::NullColumn.new(name)
  end
end

column_names()

返回一个字符串形式的列名数组。

# File activerecord/lib/active_record/model_schema.rb, line 504
def column_names
  @column_names ||= columns.map(&:name).freeze
end

columns()

# File activerecord/lib/active_record/model_schema.rb, line 429
def columns
  load_schema
  @columns ||= columns_hash.values.freeze
end

content_columns()

返回列对象数组,其中已删除主键 ID、所有以“_id”或“_count”结尾的列以及用于单表继承的列。

# File activerecord/lib/active_record/model_schema.rb, line 515
def content_columns
  @content_columns ||= columns.reject do |c|
    c.name == primary_key ||
    c.name == inheritance_column ||
    c.name.end_with?("_id", "_count")
  end.freeze
end

ignored_columns()

模型应忽略的列名列表。被忽略的列不会定义属性访问器,也不会在 SQL 查询中引用。

# File activerecord/lib/active_record/model_schema.rb, line 327
def ignored_columns
  @ignored_columns || superclass.ignored_columns
end

ignored_columns=(columns)

设置模型应忽略的列名。被忽略的列不会定义属性访问器,也不会在 SQL 查询中引用。

此方法的常见用法模式是确保已删除并部署了对属性的所有引用,然后再部署并运行从数据库中删除该列的迁移。使用这种两步方法删除列可确保在运行架构迁移时,没有代码因在内存中缓存了架构而引发错误。

例如,给定一个模型,您希望删除“category”属性,首先将其标记为忽略

class Project < ActiveRecord::Base
  # schema:
  #   id         :bigint
  #   name       :string, limit: 255
  #   category   :string, limit: 255

  self.ignored_columns += [:category]
end

架构仍然包含“category”,但现在模型省略了它,因此任何元驱动代码或架构缓存都不会尝试使用该列

Project.columns_hash["category"] => nil

如果您直接访问该属性,您将收到一条错误消息,因此请确保已删除该列的所有用法(自动化测试可以帮助您查找任何用法)。

user = Project.create!(name: "First Project")
user.category # => raises NoMethodError
# File activerecord/lib/active_record/model_schema.rb, line 362
def ignored_columns=(columns)
  reload_schema_from_cache
  @ignored_columns = columns.map(&:to_s).freeze
end

next_sequence_value()

返回将在插入语句中用作主键的下一个值。

# File activerecord/lib/active_record/model_schema.rb, line 407
def next_sequence_value
  connection.next_sequence_value(sequence_name)
end

prefetch_primary_key?()

确定是否应在插入语句之前从其相应序列中选择主键值。

# File activerecord/lib/active_record/model_schema.rb, line 401
def prefetch_primary_key?
  connection.prefetch_primary_key?(table_name)
end

protected_environments()

应禁止破坏性操作的环境名称数组。默认情况下,值为 ["production"]

# File activerecord/lib/active_record/model_schema.rb, line 308
def protected_environments
  if defined?(@protected_environments)
    @protected_environments
  else
    superclass.protected_environments
  end
end

protected_environments=(environments)

设置一个环境名称数组,其中应禁止破坏性操作。

# File activerecord/lib/active_record/model_schema.rb, line 317
def protected_environments=(environments)
  @protected_environments = environments.map(&:to_s)
end

quoted_table_name()

返回表名的引用版本,用于构造 SQL 语句。

# File activerecord/lib/active_record/model_schema.rb, line 281
def quoted_table_name
  @quoted_table_name ||= connection.quote_table_name(table_name)
end

reset_column_information()

重置有关列的所有缓存信息,这将导致它们在下次请求时重新加载。

此方法最常见的用法模式可能是在迁移中,当在创建表后,您希望使用一些默认值填充它时,例如:

class CreateJobLevels < ActiveRecord::Migration[7.1]
  def up
    create_table :job_levels do |t|
      t.integer :id
      t.string :name

      t.timestamps
    end

    JobLevel.reset_column_information
    %w{assistant executive manager director}.each do |type|
      JobLevel.create(name: type)
    end
  end

  def down
    drop_table :job_levels
  end
end
# File activerecord/lib/active_record/model_schema.rb, line 549
def reset_column_information
  connection.clear_cache!
  ([self] + descendants).each(&:undefine_attribute_methods)
  connection.schema_cache.clear_data_source_cache!(table_name)

  reload_schema_from_cache
  initialize_find_by_cache
end

sequence_name()

# File activerecord/lib/active_record/model_schema.rb, line 367
def sequence_name
  if base_class?
    @sequence_name ||= reset_sequence_name
  else
    (@sequence_name ||= nil) || base_class.sequence_name
  end
end

sequence_name=(value)

将用于生成 id 的序列名称设置为给定值,或者(如果该值为 nilfalse)设置为给定代码块返回的值。Oracle 需要此设置,并且对于任何依赖序列生成主键的数据库都很有用。

如果在使用 Oracle 时未明确设置序列名称,它将默认为常用的模式:#{table_name}_seq

如果在使用 PostgreSQL 时未明确设置序列名称,它将为您发现与您的主键相对应的序列。

class Project < ActiveRecord::Base
  self.sequence_name = "projectseq"   # default would have been "project_seq"
end
# File activerecord/lib/active_record/model_schema.rb, line 394
def sequence_name=(value)
  @sequence_name          = value.to_s
  @explicit_sequence_name = true
end

table_exists?()

指示与此类关联的表是否存在

# File activerecord/lib/active_record/model_schema.rb, line 412
def table_exists?
  connection.schema_cache.data_source_exists?(table_name)
end

table_name()

根据直接从 ActiveRecord::Base 继承的层次结构中类的名称猜测表名(强制小写)。因此,如果层次结构如下所示:Reply < Message < ActiveRecord::Base,则即使在 Reply 上调用,也会使用 Message 来猜测表名。用于进行猜测的规则由 Active Support 中的 Inflector 类处理,该类知道几乎所有常见的英语变格。您可以在 config/initializers/inflections.rb 中添加新的变格。

嵌套类获得的表名以父表的单数形式为前缀。不考虑封闭模块。

示例

class Invoice < ActiveRecord::Base
end

file                  class               table_name
invoice.rb            Invoice             invoices

class Invoice < ActiveRecord::Base
  class Lineitem < ActiveRecord::Base
  end
end

file                  class               table_name
invoice.rb            Invoice::Lineitem   invoice_lineitems

module Invoice
  class Lineitem < ActiveRecord::Base
  end
end

file                  class               table_name
invoice/lineitem.rb   Invoice::Lineitem   lineitems

此外,类级别的 table_name_prefix 被添加在前,table_name_suffix 被添加到后。因此,如果您有“myapp_”作为前缀,则 Invoice 类的表名猜测将变为“myapp_invoices”。Invoice::Lineitem 将变为“myapp_invoice_lineitems”。

Active Model Naming 的 model_name 是用于猜测表名的基本名称。如果定义了自定义 Active Model 名称,它也将用于表名

class PostRecord < ActiveRecord::Base
  class << self
    def model_name
      ActiveModel::Name.new(self, nil, "Post")
    end
  end
end

PostRecord.table_name
# => "posts"

您还可以显式设置自己的表名

class Mouse < ActiveRecord::Base
  self.table_name = "mice"
end
# File activerecord/lib/active_record/model_schema.rb, line 255
def table_name
  reset_table_name unless defined?(@table_name)
  @table_name
end

table_name=(value)

显式设置表名。示例

class Project < ActiveRecord::Base
  self.table_name = "project"
end
# File activerecord/lib/active_record/model_schema.rb, line 265
def table_name=(value)
  value = value && value.to_s

  if defined?(@table_name)
    return if value == @table_name
    reset_column_information if connected?
  end

  @table_name        = value
  @quoted_table_name = nil
  @arel_table        = nil
  @sequence_name     = nil unless defined?(@explicit_sequence_name) && @explicit_sequence_name
  @predicate_builder = nil
end

type_for_attribute(attr_name, &block)

在应用所有修饰符后,返回具有给定名称的属性的类型。此方法是与模型属性的类型相关的任何内容的唯一有效信息来源。如果需要,此方法将访问数据库并加载模型的架构。

此方法的返回值将实现由 ActiveModel::Type::Value 描述的接口(尽管对象本身可能不会对其进行子类化)。

attr_name 要检索其类型的属性的名称。必须是字符串或符号。

# File activerecord/lib/active_record/model_schema.rb, line 460
def type_for_attribute(attr_name, &block)
  attr_name = attr_name.to_s
  attr_name = attribute_aliases[attr_name] || attr_name

  if block
    attribute_types.fetch(attr_name, &block)
  else
    attribute_types[attr_name]
  end
end

实例受保护的方法

initialize_load_schema_monitor()

# File activerecord/lib/active_record/model_schema.rb, line 573
def initialize_load_schema_monitor
  @load_schema_monitor = Monitor.new
end

reload_schema_from_cache(recursive = true)

# File activerecord/lib/active_record/model_schema.rb, line 577
def reload_schema_from_cache(recursive = true)
  @_returning_columns_for_insert = nil
  @arel_table = nil
  @column_names = nil
  @symbol_column_to_string_name_hash = nil
  @attribute_types = nil
  @content_columns = nil
  @default_attributes = nil
  @column_defaults = nil
  @attributes_builder = nil
  @columns = nil
  @columns_hash = nil
  @schema_loaded = false
  @attribute_names = nil
  @yaml_encoder = nil
  if recursive
    subclasses.each do |descendant|
      descendant.send(:reload_schema_from_cache)
    end
  end
end