Active Record 自动保存关联¶ ↑
AutosaveAssociation 是一个模块,负责在父记录保存时自动保存关联记录。除了保存之外,它还会销毁所有被标记为销毁的关联记录。(请参阅 mark_for_destruction 和 marked_for_destruction?)。
父记录、其关联的保存以及被标记关联的销毁,都发生在事务内部。这应该永远不会导致数据库处于不一致的状态。
如果任何关联的验证失败,其错误消息将被应用到父记录上。
请注意,这也意味着被标记为销毁的关联不会被立即销毁。但是,它们仍然会被标记为销毁。
请注意,autosave: false 与不声明 :autosave 不同。当 :autosave 选项不存在时,新关联记录会被保存,但更新的关联记录不会被保存。
验证¶ ↑
子记录会被验证,除非 :validate 被设置为 false。
回调¶ ↑
带有 autosave 选项的关联会在你的模型上定义几个回调(around_save、before_save、after_create、after_update)。请注意,回调的执行顺序与它们在模型中定义的顺序一致。你应该避免在 autosave 回调执行之前修改关联内容。将你的回调放在关联之后通常是最佳实践。
一对一示例¶ ↑
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
注意事项¶ ↑
请注意,autosave 仅在已持久化的关联记录本身已更改时才会触发。这是为了防止由循环关联验证引起的 SystemStackError。唯一例外是当使用自定义验证上下文时,在这种情况下,验证将始终在关联记录上触发。
- A
- C
- D
- M
- R
- V
实例公共方法
autosaving_belongs_to_for?(association) Link
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 284 def autosaving_belongs_to_for?(association) @autosaving_belongs_to_for ||= {} @autosaving_belongs_to_for[association] end
changed_for_autosave?() Link
返回此记录是否已以任何方式更改(包括其任何嵌套的 autosave 关联是否同样已更改)。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 275 def changed_for_autosave? new_record? || has_changes_to_save? || marked_for_destruction? || nested_records_changed_for_autosave? end
destroyed_by_association() Link
返回正在销毁的父记录的关联。
用于避免不必要地更新计数器缓存。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 269 def destroyed_by_association @destroyed_by_association end
destroyed_by_association=(reflection) Link
记录正在被销毁的关联,并且在此过程中销毁此记录。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 262 def destroyed_by_association=(reflection) @destroyed_by_association = reflection end
mark_for_destruction() Link
标记此记录将在父记录的保存事务中被销毁。这不会立即实际销毁记录,而是子记录将在调用 parent.save 时被销毁。
仅当父记录上对此关联模型启用了 :autosave 选项时才有用。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 249 def mark_for_destruction @marked_for_destruction = true end
marked_for_destruction?() Link
返回此记录是否将在父记录的保存事务中被销毁。
仅当父记录上对此关联模型启用了 :autosave 选项时才有用。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 256 def marked_for_destruction? @marked_for_destruction end
reload(options = nil) Link
像往常一样重新加载对象的属性,并清除 marked_for_destruction 标志。
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 238 def reload(options = nil) @marked_for_destruction = false @destroyed_by_association = nil super end
validating_belongs_to_for?(association) Link
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/autosave_association.rb, line 279 def validating_belongs_to_for?(association) @validating_belongs_to_for ||= {} @validating_belongs_to_for[association] end