首页 > 解决方案 > Rails:NOT NULL Violation:保存明显的循环关联有时缺少外键

问题描述

将 Ruby-on-Rails 5.2.3 与 ruby​​ 2.5 一起使用

问题:

我在 Rails 中编写了一个网络路由器配置前端,它有一些循环定义,比如这个:

附录: 乍一看可能有点奇怪,这里有一张小图: 在此处输入图像描述可以看到两个对象之间的三个不同的关联,其中每个关联中的“地址”扮演着完全不同的角色。(但他们可以改变角色,甚至扮演多个角色——这正是应用程序的重点:始终为终端设备生成语法和逻辑上正确的配置——这部分已经起作用了)。

另外,显然还需要:

我以通常的方式构建了它:

class Forward < ApplicationRecord
  has_many :addresses, dependent: :nullify
  belongs_to :remoteip, class_name: 'Address'
  belongs_to :responding, class_name: 'Address', optional: true
end
class Address < ApplicationRecord
  belongs_to :interface
  belongs_to :forward, optional: true
  has_many :remoteip_forwards, class_name: 'Forward',
           foreign_key: :remoteip_id, dependent: :destroy
  has_many :responding_forwards, class_name: 'Forward',
           foreign_key: :responding_id, dependent: :nullify
end

然后数据库上有约束,因为对象不能是孤儿,在这种情况下:

然后我有一个顶级设计模型,它通过适当的关联将所有其他模型链接在一起,所以我可以抓住一个设计并将所有东西作为一棵树。

到目前为止,这一切都很好。但是当我尝试复制整个设计(使用deep_clonegem)时,保存时,一些相当复杂的设计给了我NotNullViolation.

分析:

日志显示 Rails 确实两次保存了一些 Address 记录:它执行了一次INSERTwith valid forward_idbut empty interface_id,然后才执行了一次UPDATEfor the valid interface_id,所有这些都在事务中。显然,这会触发NOT NULL约束,并且操作失败(删除约束时,复制成功)。

如果实际设计确实包含循环引用,我会理解这一点(因为没有其他方法可以保存它),但是没有!只有在逻辑上才有可能使用这些模型创建循环引用。

我找不到有关 Rails 如何处理此类(可能)循环事物的适当文档。inverse_of没有任何帮助(但这是可以预料的,因为我的命名是明确定义的)。

当我autosafe: false在有问题的关联上使用时,问题得到解决,Rails 保存了树 - 但是没有两次引用的记录在副本中丢失(这并不奇怪)。

因此,遍历关联树以查找和保存记录的 Rails 代码似乎并不完全广泛,并且过早地使用两次写入记录(可能是为了提高性能?)。

如何以最好的方式解决这个问题?

标签: ruby-on-railspostgresqldeep-copy

解决方案


推荐阅读