跳至内容 跳至搜索

Active Record Core

命名空间
方法
#
A
C
D
E
F
H
I
L
N
P
R
S
V

Attributes

[R] strict_loading_mode

类公共方法

attributes_for_inspect

指定将包含在 inspect 方法输出中的属性

Post.attributes_for_inspect = [:id, :title]
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!">"

当设置为 :all 时,inspect 将列出记录的所有属性

Post.attributes_for_inspect = :all
Post.first.inspect #=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
# File activerecord/lib/active_record/core.rb, line 118
class_attribute :attributes_for_inspect, instance_accessor: false, default: :all

configurations()

返回一个完全解析的 ActiveRecord::DatabaseConfigurations 对象。

# File activerecord/lib/active_record/core.rb, line 76
def self.configurations
  @@configurations
end

configurations=(config)

包含数据库配置 - 通常存储在 config/database.yml 中 - 作为 ActiveRecord::DatabaseConfigurations 对象。

例如,以下 database.yml…

development:
  adapter: sqlite3
  database: storage/development.sqlite3

production:
  adapter: sqlite3
  database: storage/production.sqlite3

…将导致 ActiveRecord::Base.configurations 如下显示

#<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
  #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
    @name="primary", @config={adapter: "sqlite3", database: "storage/development.sqlite3"}>,
  #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
    @name="primary", @config={adapter: "sqlite3", database: "storage/production.sqlite3"}>
]>
# File activerecord/lib/active_record/core.rb, line 70
def self.configurations=(config)
  @@configurations = ActiveRecord::DatabaseConfigurations.new(config)
end

connection_handler()

# File activerecord/lib/active_record/core.rb, line 132
def self.connection_handler
  ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] || default_connection_handler
end

connection_handler=(handler)

# File activerecord/lib/active_record/core.rb, line 136
def self.connection_handler=(handler)
  ActiveSupport::IsolatedExecutionState[:active_record_connection_handler] = handler
end

current_preventing_writes()

返回表示当前阻止写入设置的符号。

ActiveRecord::Base.connected_to(role: :reading) do
  ActiveRecord::Base.current_preventing_writes #=> true
end

ActiveRecord::Base.connected_to(role: :writing) do
  ActiveRecord::Base.current_preventing_writes #=> false
end
# File activerecord/lib/active_record/core.rb, line 195
def self.current_preventing_writes
  connected_to_stack.reverse_each do |hash|
    return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(Base)
    return hash[:prevent_writes] if !hash[:prevent_writes].nil? && hash[:klasses].include?(connection_class_for_self)
  end

  false
end

current_role()

返回表示当前连接角色的符号。

ActiveRecord::Base.connected_to(role: :writing) do
  ActiveRecord::Base.current_role #=> :writing
end

ActiveRecord::Base.connected_to(role: :reading) do
  ActiveRecord::Base.current_role #=> :reading
end
# File activerecord/lib/active_record/core.rb, line 158
def self.current_role
  connected_to_stack.reverse_each do |hash|
    return hash[:role] if hash[:role] && hash[:klasses].include?(Base)
    return hash[:role] if hash[:role] && hash[:klasses].include?(connection_class_for_self)
  end

  default_role
end

current_shard()

返回表示当前连接分片(shard)的符号。

ActiveRecord::Base.connected_to(role: :reading) do
  ActiveRecord::Base.current_shard #=> :default
end

ActiveRecord::Base.connected_to(role: :writing, shard: :one) do
  ActiveRecord::Base.current_shard #=> :one
end
# File activerecord/lib/active_record/core.rb, line 176
def self.current_shard
  connected_to_stack.reverse_each do |hash|
    return hash[:shard] if hash[:shard] && hash[:klasses].include?(Base)
    return hash[:shard] if hash[:shard] && hash[:klasses].include?(connection_class_for_self)
  end

  default_shard
end

destroy_association_async_batch_size

指定通过 dependent: :destroy_async 关联选项在单个后台作业中销毁的最大记录数。当为 nil(默认值)时,所有关联记录都将在单个后台作业中被销毁。如果指定了该值,则要销毁的记录将被拆分到多个后台作业中。

# File activerecord/lib/active_record/core.rb, line 46
class_attribute :destroy_association_async_batch_size, instance_writer: false, instance_predicate: false, default: nil

destroy_association_async_job()

用于在后台销毁关联的作业类。

# File activerecord/lib/active_record/core.rb, line 26
def self.destroy_association_async_job
  if _destroy_association_async_job.is_a?(String)
    self._destroy_association_async_job = _destroy_association_async_job.constantize
  end
  _destroy_association_async_job
rescue NameError => error
  raise NameError, "Unable to load destroy_association_async_job: #{error.message}"
end

enumerate_columns_in_select_statements

强制枚举 SELECT 语句中的所有列。例如,SELECT first_name, last_name FROM ... 而不是 SELECT * FROM ...。这可以避免在应用程序运行时添加数据库列时出现 PreparedStatementCacheExpired 错误。

# File activerecord/lib/active_record/core.rb, line 86
class_attribute :enumerate_columns_in_select_statements, instance_accessor: false, default: false

logger

接受一个符合 Log4r 或默认 Ruby Logger 类接口的日志记录器,该日志记录器随后会被传递给任何新的数据库连接。您可以通过在 Active Record 模型类或 Active Record 模型实例上调用 logger 来检索此日志记录器。

# File activerecord/lib/active_record/core.rb, line 21
class_attribute :logger, instance_writer: false

new(attributes = nil)

新的对象可以被实例化为两种方式:空(不传递构造参数)或预设属性但尚未保存(传递一个哈希,其键名匹配关联表列名)。在这两种情况下,有效的属性键由关联表的列名决定——因此您不能拥有不属于表列的属性。

示例

# Instantiates a single new object
User.new(first_name: 'Jamie')
# File activerecord/lib/active_record/core.rb, line 472
def initialize(attributes = nil)
  @new_record = true
  @attributes = self.class._default_attributes.deep_dup

  init_internals
  initialize_internals_callback

  super

  yield self if block_given?
  _run_initialize_callbacks
end

实例公共方法

<=>(other_object)

允许对对象进行排序

# File activerecord/lib/active_record/core.rb, line 666
def <=>(other_object)
  if other_object.is_a?(self.class)
    to_key <=> other_object.to_key
  else
    super
  end
end

==(comparison_object)

comparison_object 是完全相同的对象,或者 comparison_object 的类型相同且 self 有一个 ID 且该 ID 等于 comparison_object.id 时,返回 true。

请注意,新记录按定义与其他任何记录都不同,除非另一个记录是接收者本身。此外,如果您使用 select 获取现有记录并且不包含 ID,那么您将自行负责,此谓词将返回 false。

另请注意,销毁记录会保留其 ID 在模型实例中,因此已删除的模型仍然可比较。

也别名为: eql?
# File activerecord/lib/active_record/core.rb, line 632
def ==(comparison_object)
  super ||
    comparison_object.instance_of?(self.class) &&
    primary_key_values_present? &&
    comparison_object.id == id
end

clone

与 Ruby 的 clone 方法相同。这是一个“浅拷贝”。请注意,您的属性不会被复制。这意味着修改克隆的属性也会修改原始对象,因为它们都会指向同一个属性哈希。如果您需要复制属性哈希,请使用 dup 方法。

user = User.first
new_user = user.clone
user.name               # => "Bob"
new_user.name = "Joe"
user.name               # => "Joe"

user.object_id == new_user.object_id            # => false
user.name.object_id == new_user.name.object_id  # => true

user.name.object_id == user.dup.name.object_id  # => false
# File activerecord/lib/active_record/core.rb, line 524
    

connection_handler()

# File activerecord/lib/active_record/core.rb, line 771
def connection_handler
  self.class.connection_handler
end

dup

复制的对象没有 ID,并被视为新记录。请注意,这是一个“浅拷贝”,因为它只复制对象的属性,而不复制其关联。对象的“深拷贝”程度取决于应用程序,因此留给应用程序根据其需求来实现。dup 方法不会保留时间戳(created|updated)\_(at|on) 和锁定列。

# File activerecord/lib/active_record/core.rb, line 541
    

encode_with(coder)

使用关于此记录应序列化的属性填充 coder。此方法中定义的 coder 的结构保证与传递给 init_with 方法的 coder 的结构匹配。

示例

class Post < ActiveRecord::Base
end
coder = {}
Post.new.encode_with(coder)
coder # => {"attributes" => {"id" => nil, ... }}
# File activerecord/lib/active_record/core.rb, line 588
def encode_with(coder)
  self.class.yaml_encoder.encode(@attributes, coder)
  coder["new_record"] = new_record?
  coder["active_record_yaml_version"] = 2
end

eql?(comparison_object)

别名: ==

freeze()

克隆并冻结属性哈希,以便即使在已销毁的记录上仍然可以访问关联,但克隆的模型不会被冻结。

# File activerecord/lib/active_record/core.rb, line 655
def freeze
  @attributes = @attributes.clone.freeze
  self
end

frozen?()

如果属性哈希已被冻结,则返回 true

# File activerecord/lib/active_record/core.rb, line 661
def frozen?
  @attributes.frozen?
end

full_inspect()

将记录的所有属性作为格式良好的字符串返回,忽略 .attributes_for_inspect

Post.first.full_inspect
#=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"
# File activerecord/lib/active_record/core.rb, line 795
def full_inspect
  inspect_with_attributes(all_attributes_for_inspect)
end

hash()

委托给 id 以便能够使用类似以下的方式处理相同类型和 ID 的两个记录:

[ Person.find(1), Person.find(2), Person.find(3) ] & [ Person.find(1), Person.find(4) ] # => [ Person.find(1) ]
# File activerecord/lib/active_record/core.rb, line 642
def hash
  id = self.id

  if self.class.composite_primary_key? ? primary_key_values_present? : id
    self.class.hash ^ id.hash
  else
    super
  end
end

init_with(coder, &block)

coder 初始化一个空的模型对象。coder 应该是通过 encode_with 先前编码的 Active Record 模型的结果。

class Post < ActiveRecord::Base
end

old_post = Post.new(title: "hello world")
coder = {}
old_post.encode_with(coder)

post = Post.allocate
post.init_with(coder)
post.title # => 'hello world'
# File activerecord/lib/active_record/core.rb, line 499
def init_with(coder, &block)
  coder = LegacyYamlAdapter.convert(coder)
  attributes = self.class.yaml_encoder.decode(coder)
  init_with_attributes(attributes, coder["new_record"], &block)
end

inspect()

返回记录的属性,格式为易于阅读的字符串。

Post.first.inspect
#=> "#<Post id: 1, title: "Hello, World!", published_at: "2023-10-23 14:28:11 +0000">"

可以通过设置 .attributes_for_inspect 来限制属性。

Post.attributes_for_inspect = [:id, :title]
Post.first.inspect
#=> "#<Post id: 1, title: "Hello, World!">"
# File activerecord/lib/active_record/core.rb, line 785
def inspect
  inspect_with_attributes(attributes_for_inspect)
end

pretty_print(pp)

接受一个 PP 对象并将其记录美化打印到该对象,允许您在需要时从 pp record 获得良好结果。

# File activerecord/lib/active_record/core.rb, line 801
def pretty_print(pp)
  return super if custom_inspect_method_defined?
  pp.object_address_group(self) do
    if @attributes
      attr_names = attributes_for_inspect.select { |name| _has_attribute?(name.to_s) }
      pp.seplist(attr_names, proc { pp.text "," }) do |attr_name|
        attr_name = attr_name.to_s
        pp.breakable " "
        pp.group(1) do
          pp.text attr_name
          pp.text ":"
          pp.breakable
          value = attribute_for_inspect(attr_name)
          pp.text value
        end
      end
    else
      pp.breakable " "
      pp.text "not initialized"
    end
  end
end

readonly!()

阻止记录写入数据库

customer = Customer.new
customer.readonly!
customer.save # raises ActiveRecord::ReadOnlyRecord

customer = Customer.first
customer.readonly!
customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord

只读记录也无法从数据库中删除

customer = Customer.first
customer.readonly!
customer.destroy # raises ActiveRecord::ReadOnlyRecord

请注意,对象本身在内存中仍然是可变的

customer = Customer.new
customer.readonly!
customer.name = 'New Name' # OK

但您将无法持久化更改。

# File activerecord/lib/active_record/core.rb, line 767
def readonly!
  @readonly = true
end

readonly?()

如果记录是只读的,则返回 true

# File activerecord/lib/active_record/core.rb, line 683
def readonly?
  @readonly
end

slice(*methods)

返回一个包含给定方法及其名称作为键和返回值的哈希。

topic = Topic.new(title: "Budget", author_name: "Jason")
topic.slice(:title, :author_name)
# => { "title" => "Budget", "author_name" => "Jason" }
# File activerecord/lib/active_record/core.rb, line 595
    

strict_loading!(value = true, mode: :all)

将记录设置为严格加载模式。如果记录尝试延迟加载关联,这将引发错误。

注意:在验证期间禁用严格加载,以便记录能够验证其关联。

user = User.first
user.strict_loading! # => true
user.address.city
# => ActiveRecord::StrictLoadingViolationError
user.comments.to_a
# => ActiveRecord::StrictLoadingViolationError

参数

  • value - 布尔值,指定是启用还是禁用严格加载。

  • :mode - Symbol,指定严格加载模式。默认为 :all。使用 :n_plus_one_only 模式仅在会触发 n+1 查询的关联被延迟加载时才会引发错误。

示例

user = User.first
user.strict_loading!(false) # => false
user.address.city # => "Tatooine"
user.comments.to_a # => [#<Comment:0x00...]

user.strict_loading!(mode: :n_plus_one_only)
user.address.city # => "Tatooine"
user.comments.to_a # => [#<Comment:0x00...]
user.comments.first.ratings.to_a
# => ActiveRecord::StrictLoadingViolationError
# File activerecord/lib/active_record/core.rb, line 723
def strict_loading!(value = true, mode: :all)
  unless [:all, :n_plus_one_only].include?(mode)
    raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
  end

  @strict_loading_mode = mode
  @strict_loading = value
end

strict_loading?()

如果记录处于严格加载模式,则返回 true

# File activerecord/lib/active_record/core.rb, line 688
def strict_loading?
  @strict_loading
end

strict_loading_all?()

如果记录使用严格加载并启用了 :all 模式,则返回 true

# File activerecord/lib/active_record/core.rb, line 740
def strict_loading_all?
  @strict_loading_mode == :all
end

strict_loading_n_plus_one_only?()

如果记录使用严格加载并启用了 :n_plus_one_only 模式,则返回 true

# File activerecord/lib/active_record/core.rb, line 735
def strict_loading_n_plus_one_only?
  @strict_loading_mode == :n_plus_one_only
end

values_at(*methods)

返回由给定方法返回的值组成的数组。

topic = Topic.new(title: "Budget", author_name: "Jason")
topic.values_at(:title, :author_name)
# => ["Budget", "Jason"]
# File activerecord/lib/active_record/core.rb, line 610