ActiveRecord 何时会保存关联?
Posted
技术标签:
【中文标题】ActiveRecord 何时会保存关联?【英文标题】:When will ActiveRecord save associations? 【发布时间】:2013-09-09 16:44:19 【问题描述】:我知道它会在autosave: true
按照https://api.rubyonrails.org/classes/ActiveRecord/AutosaveAssociation.html 保存关联
我知道它会保存类似构造的关联
book = Book.new(name: 'foo') book.authors.build(name: 'bar') #has_many book.save
或喜欢
book = Book.new(name: 'foo')
book.build_author(name: 'bar') #has_one
book.save
我认为关联在分配或添加时也会保存
book = Book.new(name: 'foo') book.author = Author.new(name: 'bar') book.save
或
book = Book.new(name: 'foo')
book.authors << Author.new(name: 'bar')
book.save
但是,我有一个复杂的错误,它涉及到我期望它不会自动保存的东西。所以,我想通过检查book
来进行调试,以验证我认为要保存的内容实际上会被保存。
TL;博士;
保存关联时检查什么内部状态?我假设模型有一个内部实例变量,如associations_to_save
,关联在创建时被添加。然后,当模型被保存时,它会遍历这些关联并保存它们。
【问题讨论】:
您运行的是哪个版本的 ActiveRecord/Rails?早期版本中存在一个错误,导致它无法完全正常工作。 @PinnyM - 我使用的是最新的3.2.13
。您能否更具体地说明早期版本中哪些问题无法正常工作?
我指的是早期 2.3 版本中的错误 - 现在应该不会影响您。
ActiveRecord 自动保存关联文档的链接已损坏 - 此处为最新:api.rubyonrails.org/classes/ActiveRecord/…
【参考方案1】:
不幸的是,没有像 associations_to_save 这样的东西。但是有一些规则说明什么时候保存什么。你可以在这里找到:http://guides.rubyonrails.org/association_basics.html。分数:4.1.5 (belongs_to)、4.2.5 (has_one)、4.3.4 (has_many) 和 4.4.4 (habtm)。
更新:
在 has_many 关联的情况下,如果 child.new_record?返回 true(孩子尚未保存到 db),或者需要更新 foreign_key 列。这就是为什么:
-
将对象添加到已保存父级上的关联确实会保存新子级。
将对象添加到未保存的父节点上的关联不会保存(无外键值)
如果正在保存未保存的父对象并且在关联缓存中有一些子对象,则保存这些对象以更新 foreign_key。
【讨论】:
感谢您的尝试。名为“何时保存对象?”的部分在编码级别有帮助,但它不能回答我的问题。我想知道如何通过检查book
的当前状态来调试一个复杂的问题。我一定误解了一些很深的东西,因为我的应用程序中的某些东西没有按预期运行。
我不完全确定有什么区别。上面的部分将告诉您何时保存关联的对象,何时不保存(特别是它们解释了第一次保存对象与 n-n 关联的其他保存之间的区别),这与大多数人的想法完全不同。除了那些规则之外,没有其他方法可以说明在保存之前将保存什么(或者至少我不知道任何规则,也无法想象它会有什么用处)。你能真正发布你的错误吗?
我通读了“何时保存对象?”的所有 4 个部分,但这对我没有帮助。 (不小心按回车)我的问题是我设置了一个通过.build
构造的关联的属性,然后保存了父级。但是,关联的属性不会保存到数据库中。因此,父级并没有保存关联,它是以应该保存关联的方式之一构建的。我想通过 ActiveRecord 的方式检查关联来找出原因。因为在 ActiveRecord 的某个地方,它一定在检查什么。
啊,我最近也有同样的问题。稍后我会更新答案。
对不起,那是一个不同的问题。无论如何,如果您有两个对象并且父子对象都已保存,则保存父对象不会保存子对象。只有当 foreign_key 需要更新或孩子尚未保存时才会保存孩子(new_record? 返回 true)。【参考方案2】:
不确定这是否对其他人有帮助,但我最近在 Rails 5.2 中遇到了类似的问题。
当尝试将对象保存 2 层深度时,如果已保存顶层对象和第一层对象,我的测试将失败。 IE。
book_cover.persisted? == true
book_cover.book.persisted? == true
page = book_cover.book.pages.new
page.persisted? == false
# After saving the top level object
book_cover.save
page.persisted? == false
# After saving the immediate parent of page
book_cover.book.save
page.persisted? == true
由于父“book cover”不是新对象“page”的直接父级,因此保存“book cover”实际上并没有最终保存“page”对象。
根据情况,我只是在“book”对象上明确调用 save 来保存所有子对象。
【讨论】:
我自己没有测试过,但也许添加class BookCover < ApplicationRecord; has_one :book; has_many :pages, through: :book; end
之类的东西会让Rails了解关联? ?【参考方案3】:
我想我的回答对提问者来说太晚了 ?(当活动记录关联被保存时,我不会直接回答)但是有一些方法可以帮助深入了解对象的关联及其状态——比如 @987654327 @ 甚至(私有)方法,例如 nested_records_changed_for_autosave?
(autosave_association.rb
(API / documentation) 的一部分)或(也是私有的)association_instance_get
(在 associations.rb
内)。
注意nested_records_changed_for_autosave?
,因为它会通过嵌套的自动保存关联加载到内存中(不加载任何新关联!)。
这些方法与reflect_on_aggregation
、reflect_on_all_aggregations
、reflect_on_all_associations
、reflect_on_all_autosave_associations
、reflect_on_association
和 reflections
(API for further documentation) 等反射类方法结合使用也可能很有用,用于自动化流程像这样的关联检查:
self.class.reflect_on_all_autosave_associations #=> reflections
association_instance_get(reflection.name) #=> association
association.target #=> actual associated object(s)
object.changes #=> e. g. "name" => ["bill", "bob"]
使用target
(似乎没有很好地记录(简要提到here 或here))返回#belongs_to
和#has_one
的关联对象,或关联对象的集合对于#has_many
和#has_and_belongs_to_many
。
(我没有提供可用的代码,因为需要更多的思考来检查空数组、nil 值等等。)
在new_record?
、marked_for_destruction?
或changes
等这些关联对象方法上存在。
【讨论】:
以上是关于ActiveRecord 何时会保存关联?的主要内容,如果未能解决你的问题,请参考以下文章