如何在创建关联模型时避免不必要的加载?

问题描述 投票:0回答:1

在我的 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
,它们都会在某些时候导致不必要的负载。

ruby-on-rails ruby activerecord associations
1个回答
0
投票

您所看到的情况是由于

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

© www.soinside.com 2019 - 2024. All rights reserved.