Active Record 自動儲存關聯
AutosaveAssociation
是當其母物件儲存時,自動儲存相關記錄的模組。除了儲存之外,它還會銷毀任何已標記為要銷毀的關聯記錄。(見 mark_for_destruction
及 marked_for_destruction?
)。
儲存母物件、其關聯物件,以及銷毀已標記關聯物件,都發生在交易內。這不應讓資料庫處於不一致的狀態。
如果任何關聯物件驗證失敗,其錯誤訊息會套用給母物件。
請注意,這也表示已標記為要銷毀的關聯是不會直接被銷毀的。但它們仍會被標記為要銷毀。
請注意,autosave: false
並不與不宣告 :autosave
相同。當沒有 :autosave
選項時,新的關聯記錄會被儲存,但更新的關聯記錄將不會儲存。
驗證
子記錄會被驗證,除非 :validate
為 false
。
回呼程式
具備自動儲存選項的關聯物件會在您的模型中定義數個回呼程式(around_save、before_save、after_create、after_update)。請注意,回呼程式會依照在模型中定義的順序執行。您應避免在自動儲存回呼程式執行之前修改關聯物件內容。通常在關聯物件之後放置回呼程式會是不錯的作法。
一對一範例
class Post < ActiveRecord::Base
has_one :author, autosave: true
end
現在能自動且原子地儲存對母物件及相關模型變更。
post = Post.find(1)
post.title # => "The current global position of migrating ducks"
post.author.name # => "alloy"
post.title = "On the migration of ducks"
post.author.name = "Eloy Duran"
post.save
post.reload
post.title # => "On the migration of ducks"
post.author.name # => "Eloy Duran"
在母物件儲存動作中銷毀一個相關模型,會如標記為要銷毀般地簡單
post.author.mark_for_destruction
post.author.marked_for_destruction? # => true
請注意,此模型未從資料庫中移除
id = post.author.id
Author.find_by(id: id).nil? # => false
post.save
post.reload.author # => nil
現在已從資料庫中移除
Author.find_by(id: id).nil? # => true
一對多範例
當沒有宣告 :autosave
時,在母物件儲存時會儲存新的子物件
class Post < ActiveRecord::Base
has_many :comments # :autosave option is not declared
end
post = Post.new(title: 'ruby rocks')
post.comments.build(body: 'hello world')
post.save # => saves both post and comment
post = Post.create(title: 'ruby rocks')
post.comments.build(body: 'hello world')
post.save # => saves both post and comment
post = Post.create(title: 'ruby rocks')
comment = post.comments.create(body: 'hello world')
comment.body = 'hi everyone'
post.save # => saves post, but not comment
當 :autosave
為 true 時,會儲存所有子物件,不論它們是否為新記錄
class Post < ActiveRecord::Base
has_many :comments, autosave: true
end
post = Post.create(title: 'ruby rocks')
comment = post.comments.create(body: 'hello world')
comment.body = 'hi everyone'
post.comments.build(body: "good morning.")
post.save # => saves post and both comments.
在母物件儲存動作中銷毀其中一個相關模型,會如標記為要銷毀般地簡單
post.comments # => [#<Comment id: 1, ...>, #<Comment id: 2, ...]>
post.comments[1].mark_for_destruction
post.comments[1].marked_for_destruction? # => true
post.comments.length # => 2
請注意,此模型未從資料庫中移除
id = post.comments.last.id
Comment.find_by(id: id).nil? # => false
post.save
post.reload.comments.length # => 1
現在已從資料庫中移除
Comment.find_by(id: id).nil? # => true
注意事項
請注意,自動儲存只會觸發已儲存的關聯物件記錄(前提是記錄本身已變更)。這可防止由循環關聯驗證所導致的 SystemStackError
。但有一個例外,即使用了自訂的驗證內容,此時驗證會持續在相關記錄上觸發。
- A
- C
- D
- M
- R
- V
執行個體的公開方法
autosaving_belongs_to_for?(關聯) 連結
changed_for_autosave?() 連結
傳回此記錄是否已任何方式變更 (包括任何巢狀自動儲存關聯也已變更)
destroyed_by_association() 連結
傳回要毀損的父關聯。
用於避免不必要地更新反向快取。
destroyed_by_association=(reflection) 連結
記錄要毀損且毀損這個記錄的關聯。
mark_for_destruction() 連結
標記這個記錄為在父儲存交易中被毀損的一部分。這不會立即毀損這個記錄,而是會在呼叫 parent.save
時毀損子記錄。
只有在這個關聯模型已啟用父的 :autosave
選項時才有用。
marked_for_destruction?() 連結
傳回這個記錄是否會在父儲存交易中毀損。
只有在這個關聯模型已啟用父的 :autosave
選項時才有用。
reload(options = nil) 連結
重新載入物件的屬性並清除 marked_for_destruction
旗標。