在我的 Rails 应用程序中,我们有几个与此类似的模型
class Pen < ActiveRecord::Base
has_one :ink
after_create :add_ink
def add_ink
create_ink(color: "blue")
end
end
class Ink < ActiveRecord::Base
belongs_to :pen
end
在控制器中我们做这样的事情
pen = Pen.new(..)
pen.save
从概念上讲,Pen 总是有一个 Ink,我们在创建 Pen 时创建 Ink。 (也欢迎比 after_create 挂钩更好的方法来完成此任务)。
问题是它总是为关联发出 SELECT,即使那里保证什么也没有。
[DEBUG] TRANSACTION (0.2ms) BEGIN
[DEBUG] Pen Create (1.5ms) INSERT INTO pens ("owner_id") VALUES ('00f74077-c079-4482-aa03-15b23951a7bd') RETURNING "id"
[DEBUG] Ink Load (0.4ms) SELECT "inks".* FROM "inks" WHERE "inks"."pen_id" = '93a45bae-2cf3-48c1-ac00-6b3059dca5ae' LIMIT 1
[DEBUG] Ink Create (0.3ms) INSERT INTO "inks" ("pen_id", "color") VALUES ('93a45bae-2cf3-48c1-ac00-6b3059dca5ae', 'blue') RETURNING "pen_id"
[DEBUG] TRANSACTION (0.2ms) COMMIT
具体来说,这不应该发生
[DEBUG] Ink Load (0.4ms) SELECT "inks".* FROM "inks" WHERE "inks"."pen_id" = '93a45bae-2cf3-48c1-ac00-6b3059dca5ae' LIMIT 1
我尝试过使用
build_association
后接 save
、create_association
,以及使用 association=
和 Association.create
,它们都会在某些时候导致不必要的负载。
您所看到的情况是由于
Pen
已经持久存在,因为 Ink 的创建发生在创建后。
来自文档
- 将对象分配给
关联会自动保存该对象和正在替换的对象(如果有),以便更新它们的外键 - 除非父对象未保存 (has_one
)。new_record? == true
- 如果其中任何一个保存失败(由于其中一个对象无效),则会引发
异常并取消分配。ActiveRecord::RecordNotSaved
所以你看到的是rails试图确定关联的记录是否已经存在。
取决于您想要的结果,您可以尝试
Ink.create(pen_id: self.id, color: 'blue')
;不过我认为将其移至 before_create
操作可能会更好,例如
class Pen < ActiveRecord::Base
has_one :ink
before_create :add_ink
def add_ink
build_ink(color: "blue")
end
end
根据文档
:自动保存 如果为 true,则在保存父对象时,始终保存关联对象或销毁它(如果标记为销毁)。如果为 false,则绝不保存或销毁关联的对象。默认情况下,如果是新记录,则仅保存关联对象。
因此,由于这是一个
before_create
,因此 Pen
是一个新记录,因此它也应该保存 Ink
。