0

has_one 关联方法对我来说执行不一致,我不知道为什么。

取两个相互关联的简单模型:

class Container < ActiveRecord::Base
  has_one: :super
end

class Super < ActiveRecord::Base
  belongs_to: :container
end

以下代码可以正常工作:

container = Container.create
 ...

container.build_super
 ...
 => #<Super id: nil, container_id: 1, content: nil, created_at: nil, updated_at: nil>

container.super
 => #<Super id: nil, container_id: 1, content: nil, created_at: nil, updated_at: nil>

在上述代码中调用 container.super 时,它会返回新建的 Super 类实例。

但是,以下代码不起作用:

Container.create
 ...
 => #<Container id: 1, created_at: "2013-10-26 20:31:26", updated_at: "2013-10-26 20:31:26">

Container.first.build_super
 ...
 => #<Super id: nil, container_id: 1, content: nil, created_at: nil, updated_at: nil>

Container.first.super
  Container Load (0.2ms)  SELECT "containers".* FROM "containers" ORDER BY "containers"."id" ASC LIMIT 1
  Super Load (0.1ms)  SELECT "supers".* FROM "supers" WHERE "supers"."container_id" = ? ORDER BY "supers"."id" ASC LIMIT 1  [["container_id", 1]]
 => nil

Container.first.super 返回 nil,因为它似乎正在数据库中寻找 Super 的实例。但是,该实例尚未提交。

但是为什么 container.super 和 Container.first.super 在 container == Container.first 时不会产生相同的结果?

4

2 回答 2

2

在您的第一个示例中,超级对象是在内存中构建的,并且在您从数据库中重新加载它时会丢失(如您的第二个示例所示)。如果您要container.reload.super在第一个示例中从数据库中加载它,那么内存中的对象将会丢失并且它为零。

旁注:将您的协会命名为“超级”是一个非常糟糕的主意。这是 Ruby 中的保留关键字,用于在子类覆盖父类时调用父类的方法。

于 2013-10-26T21:14:59.383 回答
2

Container.first.build_super获取 Container 记录的副本,构建关联实例,并将此关联实例缓存在 Container 记录的该副本中。

在此之后调用Container.first.super会获取 Container 记录的单独副本,并发现它没有任何内容:super

本质上,您正在这样做:

a = Container.first    # New instance
a.build_super          # Assign to :super

b = Container.first    # Separate instance
b.super                # Nothing in :super

您可能想要做的是将其分配给变量而不是获取另一个副本:

container = Container.first
container.build_super
container.super
于 2013-10-26T21:20:19.053 回答