在我的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
从概念上讲,钢笔总是有墨水,我们在创建钢笔时创建墨水。(也可以使用比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
,它们都在某些时候导致不必要的负载。
2条答案
按热度按时间4uqofj5v1#
您所看到的是由于在
after_create
中创建Ink
时,Pen
已经被持久化了。从Docs
has_one
关联会自动保存该对象和被替换的对象(如果有的话),以便更新它们的外键-除非父对象未保存(new_record? == true
)。ActiveRecord::RecordNotSaved
异常并取消赋值。所以你看到的是rails试图确定相关的记录是否已经存在,这样就可以相应地更新它。
根据您想要的结果,您可以尝试
Ink.create(pen_id: self.id, color: 'blue')
;然而,我认为仅仅将其移动到before_create
操作可能是一个更好的实现,例如。据《纽约时报》报道,
:自动保存
如果为true,则在保存父对象时,始终保存关联对象或销毁关联对象(如果标记为销毁)。如果为false,则从不保存或销毁关联对象。默认情况下,仅当关联对象是新记录时才保存该对象。
因为这是一个
before_create
,所以Pen
是一个新记录,因此它也应该保存Ink
,而不需要查询数据库。i1icjdpr2#
如果你需要一些空笔(没有墨水)怎么办?
如果你需要一支有绿色墨水的笔呢?
我建议这样做
在这种情况下,你可以这样称呼它: