:autosave 忽略了 has_many 关系——我错过了啥?

Posted

技术标签:

【中文标题】:autosave 忽略了 has_many 关系——我错过了啥?【英文标题】::autosave ignored on has_many relation -- what am I missing?:autosave 忽略了 has_many 关系——我错过了什么? 【发布时间】:2012-07-23 00:23:53 【问题描述】:

我有一对类:

class Collection < ActiveRecord::Base                                                                                                                                                                                                         
  has_many :items, autosave: true
end

class Item < ActiveRecord::Base
  belongs_to :collection
end

来自docs:

当 :autosave 为 true 时,所有子项都会被保存,无论它们是否是新记录:

但是当我更新 Item 并保存其父 Collection 时,Item 的更新属性不会被保存:

 > c = Collection.first
 => #<Collection id: 1, name: "collection", created_at: "2012-07-23 00:00:10", updated_at: "2012-07-23 00:00:10"> 
 > i = c.items.first
 => #<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25"> 
 > i.name = 'new name'
 => "new name" 
 > c.save
 => true 
 > Collection.first.items
 => [#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">]

那么,我错过了什么?

我正在使用 Rails 3.2.5 和 Ruby 1.9.2。


所以我已经对 ActiveRecord 的源进行了一些挖掘。我们可以获取c的自动保存关联:

 > c.class.reflect_on_all_autosave_associations
 => [#<ActiveRecord::Reflection::AssociationReflection:0x007fece57b3bd8 @macro=:has_many, @name=:items, @options=:autosave=>true, :extend=>[], @active_record=Collection(id: integer, name: string, created_at: datetime, updated_at: datetime), @plural_name="items", @collection=true, @class_name="Item", @klass=Item(id: integer, collection_id: integer, name: string, created_at: datetime, updated_at: datetime), @foreign_key="collection_id", @active_record_primary_key="id", @type=nil>]

我认为这说明该关联已设置为自动保存。

然后我们可以得到c对应的关联实例:

 > a = c.send :association_instance_get, :items
 => #<ActiveRecord::Associations::HasManyAssociation:0x007fece738e920 @target=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], @reflection=#<ActiveRecord::Reflection::AssociationReflection:0x007fece57b3bd8 @macro=:has_many, @name=:items, @options=:autosave=>true, :extend=>[], @active_record=Collection(id: integer, name: string, created_at: datetime, updated_at: datetime), @plural_name="items", @collection=true, @class_name="Item", @klass=Item(id: integer, collection_id: integer, name: string, created_at: datetime, updated_at: datetime), @foreign_key="collection_id", @active_record_primary_key="id", @type=nil>, @owner=#<Collection id: 1, name: "collection", created_at: "2012-07-23 00:00:10", updated_at: "2012-07-23 00:00:10">, @updated=false, @loaded=true, @association_scope=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], @proxy=[#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">], @stale_state=nil> 

然后我们可以找到通过这个关联关联的实际对象:

 > a.target
 => [#<Item id: 1, collection_id: 1, name: "item1", created_at: "2012-07-23 00:00:25", updated_at: "2012-07-23 00:00:25">]

在此处找到的对象没有我之前所做的更新。

【问题讨论】:

【参考方案1】:

这里的问题是行

 i = c.items.first

这一行从数据库中提取了正确的项目,但没有将它附加到集合 c。它是与对象不同的红宝石对象

i = c.items[0]

如果您将第一行替换为第二行,您的示例将起作用。

【讨论】:

谢谢。在这里我想 .first == [0] 通常基本上是这样。这种差异是由 Rails 将#first 转换为 SQL 谓词造成的。你可以在这里看到 Ruby #first 的 C 源代码:ruby-doc.org/core-2.1.3/Enumerable.html#method-i-first 和 Ralis 的关系:github.com/rails/rails/blob/…

以上是关于:autosave 忽略了 has_many 关系——我错过了啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 has_many 关系中急切加载最新的对象?

通过同一模型的两个 has_many 关系

从 has_many 更改为 has_one 关系轨

Rails RSpec 测试 has_many :through 关系

使用 has_many 关系保存记录

如何修改依赖::destroy 查询 has_many 关系