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 &lt; 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_aggregationreflect_on_all_aggregationsreflect_on_all_associationsreflect_on_all_autosave_associationsreflect_on_associationreflections (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 何时会保存关联?的主要内容,如果未能解决你的问题,请参考以下文章

ActiveRecord 在保存主对象时是不是保存了belongs_to 关联?

rails 获取多态类的所有关联类

活动记录关联未保存在数据库中

ActiveRecord 查找所有有关联孩子的父母

PHP ActiveRecord - 在模型中找不到关联

Rails 关联不保存