Active Record 持久性
- B
- D
- I
- N
- P
- R
- S
- T
- U
實體公開方法
becomes(klass) 連結
傳回具有目前記錄屬性的指定 klass
的實體。這在單一資料表繼承 (STI) 結構中特別有用,其中您希望子類別顯示為超類別。可以將此與 Action Pack 中的記錄識別一起使用,例如,Client < Company
進行類似於將該實體使用公司/公司部分而非客戶/客戶的部分來呈式的 partial: @client.becomes(Company)
呈式。
注意:新實體將與原始類別共享連結至相同屬性的連結。因此,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) 的值。減法直接執行在基礎屬性上,未呼叫任何設定程式。僅適用於基於數字的屬性。傳回 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
,將 屬性
初始化為零,並加上視為 by
傳遞的值(預設為 1)。遞增作業會直接在基本屬性上執行,不會呼叫任何設定函式。僅針對基於數字的屬性才有意義。傳回 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!(屬性, by = 1, touch: nil) 連結
包覆在 increment
中,將更新寫入資料庫。僅更新 屬性
;記錄本身不會儲存。也就是說,任何其他修改的屬性仍然會是髒的。驗證
和 callback 會被略過。支援來自 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(選項 = 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: 'account@example.com'>
屬性
會從資料庫重新載入,並清除快取,特別是關聯快取和 查詢快取
。
如果記錄不再存在於資料庫,則會引发 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
。
如果紀錄正在更新中,會靜默略過標記為唯讀的 屬性
。
來源:顯示 | 在 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
。
如果紀錄正在更新中,會靜默略過標記為唯讀的 屬性
。
除非發生錯誤,否則會傳回 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
。這個方法直接切換底層值,而不會呼叫任何設定函式。傳回 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
的包裝器,用以儲存紀錄。此方法不同於其非驚嘆版本的概念是,它會傳遞屬性設定器。儲存不受驗證檢查約束。如果可以儲存紀錄,則傳回 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