Rails:NOT NULL违反:保存明显的循环关联有时缺少外键

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

问题:

我已经在Rails中编写了一个网络路由器配置前端,它具有一些循环定义,如下所示:

  • 转发具有许多地址(已转发)。
  • 地址有许多转发(可转发给它)。
  • 一个地址有很多转发(来自它的响应)。

附录: 乍一看可能有点奇怪,所以下面是一些图片:

Rails:NOT NULL违反:保存明显的循环关联有时缺少外键

可以看到两个对象之间的三个不同的关联,其中每个关联中的“地址”扮演着完全不同的角色。 (但是他们可以更改角色,甚至可以扮演多个角色-这正是应用程序的要点:始终为终端设备生成语法和逻辑上正确的配置-并且该部分已经起作用了。)

此外,显然还需要:

  • 地址属于接口。

我以通常的方式构建它:

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,foreign_key: :responding_id,dependent: :nullify
end

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

  • address.interface_id不为空

然后,我有了一个顶层设计模型,该模型通过适当的关联将所有其他模型链接在一起,因此我可以抓取一个设计并将所有东西都当成一棵树。

到目前为止,一切都很好。但是,当我尝试复制整个设计(带有deep_clone宝石)时,保存时,一些相当复杂的设计给了我NotNullViolation

分析:

日志显示,Rails确实保存了一些地址记录两次:它使用有效的INSERT进行了forward_id,但 {{1 }},直到以后,interface_id才对有效UPDATE生效,所有事务都在其中。 显然,这会触发interface_id约束,并且操作失败(删除约束时,复制成功完成)。

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

我找不到有关Rails如何处理此类(潜在)循环事物的适当文档。 NOT NULL并没有任何帮助(但这是意料之中的,因为我的名字定义明确)。

当我在有问题的关联上使用inverse_of时,问题已解决,Rails保存了树-但随后副本中缺少了两次未引用的记录(这不足为奇)。

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

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

  • 可悲的是,autosafe: false约束在Postgresql中不是NOT NULL。太糟糕了,因为这似乎是最迷人的解决方案。
  • 使用DEFERrablE,步行走关联树以找到正确的顺序并分别保存每个记录?不用了。
  • 以某种方式布置关联?怎么样? (我已经有了可以转换目标设备的所有数据的工作代码,并且可以与当前布局很好地工作。)
  • 放弃NOT NULL约束吗?嗯...
  • 或者,Rails中是否有可以调节的旋钮?
yangleilgone 回答:Rails:NOT NULL违反:保存明显的循环关联有时缺少外键

暂时没有好的解决方案,如果你有好的解决方案,请发邮件至:iooj@foxmail.com
本文链接:https://www.f2er.com/3136986.html

大家都在问