Active Record 持久性
- B
- D
- I
- N
- P
- R
- S
- T
- U
实例公共方法
becomes(klass) 链接
返回指定 klass
的实例,该实例具有当前记录的属性。这在单表继承 (STI) 结构中非常有用,在这种结构中,您希望子类显示为超类。这可以与 Action Pack 中的记录标识一起使用,以允许,例如,Client < Company
执行类似于渲染 partial: @client.becomes(Company)
的操作,以使用 companies/company 部分而不是 clients/client 渲染该实例。
注意:新实例将共享与原始类相同的属性链接。因此,STI 列值将保持不变。对任一实例的属性的任何更改都将影响这两个实例。这包括新实例完成的任何属性初始化。
如果要更改 STI 列,请改用 becomes!
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 487 def becomes(klass) became = klass.allocate became.send(:initialize) do |becoming| @attributes.reverse_merge!(becoming.instance_variable_get(:@attributes)) becoming.instance_variable_set(:@attributes, @attributes) becoming.instance_variable_set(:@mutations_from_database, @mutations_from_database ||= nil) becoming.instance_variable_set(:@new_record, new_record?) becoming.instance_variable_set(:@destroyed, destroyed?) becoming.errors.copy!(errors) end became end
becomes!(klass) 链接
围绕 becomes
的包装器,它还会更改实例的 STI 列值。如果您希望在数据库中持久化更改的类,这将特别有用。
注意:旧实例的 STI 列值也将被更改,因为这两个对象共享相同的属性集。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 508 def becomes!(klass) became = becomes(klass) sti_type = nil if !klass.descends_from_active_record? sti_type = klass.sti_name end became.public_send("#{klass.inheritance_column}=", sti_type) became end
decrement(attribute, by = 1) 链接
如果 nil
,则将 attribute
初始化为零,并减去作为 by
传递的值(默认值为 1)。递减直接在底层属性上执行,不会调用 setter。仅对基于数字的属性有意义。返回 self
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 655 def decrement(attribute, by = 1) increment(attribute, -by) end
decrement!(attribute, by = 1, touch: nil) 链接
围绕 decrement
的包装器,该包装器将更新写入数据库。仅更新 attribute
;不会保存记录本身。这意味着任何其他修改的属性将仍然是脏的。Validations
和回调被跳过。支持 update_counters
中的 touch
选项,请参阅以了解更多信息。返回 self
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 665 def decrement!(attribute, by = 1, touch: nil) increment!(attribute, -by, touch: touch) end
delete() 链接
从数据库中删除记录,并将此实例冻结以反映不应该进行任何更改(因为它们无法持久化)。返回冻结的实例。
该行只是使用 SQL DELETE
语句在记录的主键上删除,不会执行任何回调。
请注意,这也会删除标记为 #readonly? 的记录。
要强制执行对象的 before_destroy
和 after_destroy
回调或任何 :dependent
关联选项,请使用 destroy
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 439 def delete _delete_row if persisted? @destroyed = true @previously_new_record = false freeze end
destroy() 链接
从数据库中删除记录,并将此实例冻结以反映不应该进行任何更改(因为它们无法持久化)。
有一系列与 destroy
关联的回调。如果 before_destroy
回调抛出 :abort
,则操作将被取消,destroy
将返回 false
。有关更多详细信息,请参阅 ActiveRecord::Callbacks
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 453 def destroy _raise_readonly_record_error if readonly? destroy_associations @_trigger_destroy_callback ||= persisted? && destroy_row > 0 @destroyed = true @previously_new_record = false freeze end
destroy!() 链接
从数据库中删除记录,并将此实例冻结以反映不应该进行任何更改(因为它们无法持久化)。
有一系列与 destroy!
关联的回调。如果 before_destroy
回调抛出 :abort
,则操作将被取消,destroy!
将引发 ActiveRecord::RecordNotDestroyed
。有关更多详细信息,请参阅 ActiveRecord::Callbacks
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 469 def destroy! destroy || _raise_record_not_destroyed end
destroyed?() 链接
如果此对象已被销毁,则返回 true,否则返回 false。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 355 def destroyed? @destroyed end
increment(attribute, by = 1) 链接
如果 nil
,则将 attribute
初始化为零,并添加作为 by
传递的值(默认值为 1)。递增直接在底层属性上执行,不会调用 setter。仅对基于数字的属性有意义。返回 self
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 632 def increment(attribute, by = 1) self[attribute] ||= 0 self[attribute] += by self end
increment!(attribute, by = 1, touch: nil) 链接
围绕 increment
的包装器,该包装器将更新写入数据库。仅更新 attribute
;不会保存记录本身。这意味着任何其他修改的属性将仍然是脏的。Validations
和回调被跳过。支持 update_counters
中的 touch
选项,请参阅以了解更多信息。返回 self
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 644 def increment!(attribute, by = 1, touch: nil) increment(attribute, by) change = public_send(attribute) - (public_send(:"#{attribute}_in_database") || 0) self.class.update_counters(id, attribute => change, touch: touch) public_send(:"clear_#{attribute}_change") self end
new_record?() 链接
如果此对象尚未保存 - 即数据库中尚不存在该对象的记录 - 则返回 true;否则返回 false。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 338 def new_record? @new_record end
persisted?() 链接
如果记录已持久化,即它不是新记录并且没有被销毁,则返回 true,否则返回 false。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 361 def persisted? !(@new_record || @destroyed) end
previously_new_record?() 链接
如果此对象刚刚创建 - 即在上次更新或删除之前,该对象在数据库中不存在并且 new_record? 将返回 true - 则返回 true。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 345 def previously_new_record? @previously_new_record end
previously_persisted?() 链接
如果此对象先前已持久化但现在已删除,则返回 true。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 350 def previously_persisted? !new_record? && destroyed? end
reload(options = nil) 链接
从数据库中重新加载记录。
此方法通过其主键(可以手动分配)查找记录,并就地修改接收器
account = Account.new
# => #<Account id: nil, email: nil>
account.id = 1
account.reload
# Account Load (1.2ms) SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1 [["id", 1]]
# => #<Account id: 1, email: '[email protected]'>
Attributes
从数据库重新加载,并清除缓存,特别是关联缓存和 QueryCache
。
如果记录不再存在于数据库中,则会引发 ActiveRecord::RecordNotFound
。否则,除了就地修改之外,该方法还会为了方便而返回 self
。
可选的 :lock
标志选项允许您锁定重新加载的记录。
reload(lock: true) # reload with pessimistic locking
重新加载通常用于测试套件,以测试某些内容是否已实际写入数据库,或者当某些操作修改了数据库中相应的行但未修改内存中的对象时。
assert account.deposit!(25)
assert_equal 25, account.credit # check it is updated in memory
assert_equal 25, account.reload.credit # check it is also persisted
另一个常见的用例是乐观锁处理。
def with_optimistic_retry
begin
yield
rescue ActiveRecord::StaleObjectError
begin
# Reload lock_version in particular.
reload
rescue ActiveRecord::RecordNotFound
# If the record is gone there is nothing to do.
else
retry
end
end
end
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 742 def reload(options = nil) self.class.connection_pool.clear_query_cache fresh_object = if apply_scoping?(options) _find_record((options || {}).merge(all_queries: true)) else self.class.unscoped { _find_record(options) } end @association_cache = fresh_object.instance_variable_get(:@association_cache) @association_cache.each_value { |association| association.owner = self } @attributes = fresh_object.instance_variable_get(:@attributes) @new_record = false @previously_new_record = false self end
save(**options) 链接
保存模型。
如果模型是新的,则在数据库中创建一个记录,否则更新现有记录。
默认情况下,save 始终运行验证。如果任何验证失败,则操作将被取消,save
返回 false
,并且记录将不会被保存。但是,如果您提供 validate: false
,则验证将完全绕过。有关更多信息,请参见 ActiveRecord::Validations
。
默认情况下,save
还会将 updated_at
/updated_on
属性设置为当前时间。但是,如果您提供 touch: false
,这些时间戳将不会更新。
与 save
相关联的是一系列回调。如果任何 before_*
回调抛出 :abort
,则操作将被取消,save
返回 false
。有关更多详细信息,请参见 ActiveRecord::Callbacks
。
如果记录正在更新,则标记为只读的 Attributes
会被静默忽略。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 390 def save(**options, &block) create_or_update(**options, &block) rescue ActiveRecord::RecordInvalid false end
save!(**options) 链接
保存模型。
如果模型是新的,则在数据库中创建一个记录,否则更新现有记录。
默认情况下,save!
始终运行验证。如果任何验证失败,则会引发 ActiveRecord::RecordInvalid
,并且记录将不会被保存。但是,如果您提供 validate: false
,则验证将完全绕过。有关更多信息,请参见 ActiveRecord::Validations
。
默认情况下,save!
还会将 updated_at
/updated_on
属性设置为当前时间。但是,如果您提供 touch: false
,这些时间戳将不会更新。
与 save!
相关联的是一系列回调。如果任何 before_*
回调抛出 :abort
,则操作将被取消,save!
会引发 ActiveRecord::RecordNotSaved
。有关更多详细信息,请参见 ActiveRecord::Callbacks
。
如果记录正在更新,则标记为只读的 Attributes
会被静默忽略。
除非引发错误,否则返回 true。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 423 def save!(**options, &block) create_or_update(**options, &block) || raise(RecordNotSaved.new("Failed to save the record", self)) end
toggle(attribute) 链接
将 attribute
赋值为 attribute?
的布尔值相反。因此,如果谓词返回 true
,则属性将变为 false
。此方法直接切换底层值,不会调用任何 setter。返回 self
。
示例
user = User.first
user.banned? # => false
user.toggle(:banned)
user.banned? # => true
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 681 def toggle(attribute) self[attribute] = !public_send("#{attribute}?") self end
toggle!(attribute) 链接
围绕 toggle
的包装器,用于保存记录。此方法与其非感叹号版本的不同之处在于它通过属性 setter 传递。保存不受验证检查的约束。如果记录可以保存,则返回 true
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 690 def toggle!(attribute) toggle(attribute).update_attribute(attribute, self[attribute]) end
touch(*names, time: nil) 链接
保存记录,并将 updated_at
/on
属性设置为当前时间或指定的时间。请注意,不会执行任何验证,并且仅执行 after_touch
、after_commit
和 after_rollback
回调。
此方法可以传递属性名称和可选的时间参数。如果传递属性名称,则它们会与 updated_at
/on
属性一起更新。如果没有传递时间参数,则默认使用当前时间。
product.touch # updates updated_at/on with current time
product.touch(time: Time.new(2015, 2, 16, 0, 0, 0)) # updates updated_at/on with specified time
product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes
如果与 belongs_to 一起使用,则 touch
将在关联对象上调用 touch
方法。
class Brake < ActiveRecord::Base
belongs_to :car, touch: true
end
class Car < ActiveRecord::Base
belongs_to :corporation, touch: true
end
# triggers @brake.car.touch and @brake.car.corporation.touch
@brake.touch
请注意,touch
必须用于已持久化的对象,否则会抛出 ActiveRecordError
。例如
ball = Ball.new
ball.touch(:updated_at) # => raises ActiveRecordError
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 793 def touch(*names, time: nil) _raise_record_not_touched_error unless persisted? _raise_readonly_record_error if readonly? attribute_names = timestamp_attributes_for_update_in_model attribute_names = (attribute_names | names).map! do |name| name = name.to_s name = self.class.attribute_aliases[name] || name verify_readonly_attribute(name) name end unless attribute_names.empty? affected_rows = _touch_row(attribute_names, time) @_trigger_update_callback = affected_rows == 1 else true end end
update(attributes) 链接
从传入的哈希中更新模型的属性,并保存记录,所有这些都包装在一个事务中。如果对象无效,则保存将失败,并将返回 false。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 563 def update(attributes) # The following transaction covers any possible database side-effects of the # attributes assignment. For example, setting the IDs of a child collection. with_transaction_returning_status do assign_attributes(attributes) save end end
update!(attributes) 链接
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 574 def update!(attributes) # The following transaction covers any possible database side-effects of the # attributes assignment. For example, setting the IDs of a child collection. with_transaction_returning_status do assign_attributes(attributes) save! end end
update_attribute(name, value) 链接
更新单个属性并保存记录。这对于现有记录上的布尔标志特别有用。另请注意
-
验证将被跳过。
-
回调将被调用。
-
如果该列可用,则更新
updated_at
/updated_on
列。 -
更新此对象中所有已脏的属性。
如果属性被标记为只读,则此方法会引发 ActiveRecord::ActiveRecordError
。
另请参见 update_column
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 530 def update_attribute(name, value) name = name.to_s verify_readonly_attribute(name) public_send("#{name}=", value) save(validate: false) end
update_attribute!(name, value) 链接
更新单个属性并保存记录。这对于现有记录上的布尔标志特别有用。另请注意
-
验证将被跳过。
-
回调将被调用。
-
如果该列可用,则更新
updated_at
/updated_on
列。 -
更新此对象中所有已脏的属性。
如果属性被标记为只读,则此方法会引发 ActiveRecord::ActiveRecordError
。
如果任何 before_*
回调抛出 :abort
,则操作将被取消,update_attribute!
会引发 ActiveRecord::RecordNotSaved
。有关更多详细信息,请参见 ActiveRecord::Callbacks
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 552 def update_attribute!(name, value) name = name.to_s verify_readonly_attribute(name) public_send("#{name}=", value) save!(validate: false) end
update_column(name, value) 链接
等效于 update_columns(name => value)
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 584 def update_column(name, value) update_columns(name => value) end
update_columns(attributes) 链接
直接在数据库中更新属性,发出 UPDATE SQL 语句,并在接收器中设置它们
user.update_columns(last_request_at: Time.current)
这是更新属性的最快方法,因为它直接转到数据库,但请注意,结果是完全绕过常规更新过程。尤其是
-
验证将被跳过。
-
回调将被跳过。
-
updated_at
/updated_on
不会更新。 -
但是,属性使用与
ActiveRecord::Relation#update_all
相同的规则进行序列化
当对新对象调用此方法时,或者当至少一个属性被标记为只读时,此方法会引发 ActiveRecord::ActiveRecordError
。
来源:显示 | 在 GitHub 上
# File activerecord/lib/active_record/persistence.rb, line 604 def update_columns(attributes) raise ActiveRecordError, "cannot update a new record" if new_record? raise ActiveRecordError, "cannot update a destroyed record" if destroyed? _raise_readonly_record_error if readonly? attributes = attributes.transform_keys do |key| name = key.to_s name = self.class.attribute_aliases[name] || name verify_readonly_attribute(name) || name end update_constraints = _query_constraints_hash attributes = attributes.each_with_object({}) do |(k, v), h| h[k] = @attributes.write_cast_value(k, v) clear_attribute_change(k) end affected_rows = self.class._update_record( attributes, update_constraints ) affected_rows == 1 end