由于多列上的唯一索引,无法更新 Rails 中的父记录和嵌套记录

Posted

技术标签:

【中文标题】由于多列上的唯一索引,无法更新 Rails 中的父记录和嵌套记录【英文标题】:Unable to update parent and nested records in rails because of unique index on multiple columns 【发布时间】:2016-05-18 21:56:29 【问题描述】:

我通过has_many 关联创建了一个带有嵌套记录的父模型,并允许通过accepts_nested_attributes_for 更新嵌套记录。 我的嵌套记录具有 order 属性,该属性在 parent_id 范围内应该是唯一的。我知道我可以使用带有 :scope 的 Rails 唯一性验证,但我决定使用唯一的多列索引。

所以,假设我有父模型Race

class Race < ActiveRecord::Base
  has_many :drivers
  accept_nested_attributes_for :drivers, allow_destroy: true
end

并嵌套Drivers:

class Driver < ActiveRecord::Base
  belongs_to :race
  validates :order, numericality:  only_integer: true,
                                    greater_than_or_equal_to: 0 
end

我还创建了我的唯一索引:

class AddUniqueIndexOnDriversOrder < ActiveRecord::Migration
  def change
    add_index :drivers, [:order, :race_id], unique: true
  end
end

不幸的是,使用此设置,我无法更改以前在 Race 中创建的 Drivers 的顺序。当我想用Drivers 更新Race 并为每个Driver 记录新的完全有效的订单时,Rails 不会将此更新作为一个事务执行,并且我的索引会中断整个操作。任何提示如何保持数据库约束并能够在一次操作中使用嵌套记录更新父对象?

【问题讨论】:

您使用什么代码进行更新?可以对其进行更改以使其正常工作。 @MichaelGaskill 我尝试使用标准 Rails 方法:Race.update(race_params) 我的意思是,您使用的是哪种逻辑?请显示进行update 调用的代码块。处理为比赛分配车手顺序的整个模块。这就是关键。 @MichaelGaskill 我只是将所有记录发送到控制器。假设这个简单的例子,在 DB 中有一个 Raceid:1 和两个 Driversid: 1, order:1id:2, order:2 我想更新它并将属性发送到我的控制器:race:id:1, drivers_attributes:[id:1, order:2, id:2, order:1]。当 Rails 使用 id 1 更新嵌套驱动程序时,存在约束冲突... 【参考方案1】:

经过几个小时的搜索和挖掘,我终于找到了问题的答案!该解决方案在数据库中使用DEFERRABLE CONSTRAINTS,这是我以前不知道的。

这类约束不必立即运行,它们可以在事务结束时执行检查。

https://hashrocket.com/blog/posts/deferring-database-constraints 完美地描述了这种确切的情况。

【讨论】:

以上是关于由于多列上的唯一索引,无法更新 Rails 中的父记录和嵌套记录的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Rails 3.2 中使用复合唯一索引将记录添加到连接表

由于在同一 SaveChanges 中删除的记录中的值,实体更新在唯一索引上失败

带表达式的多列索引(PostgreSQL 和 Rails)

索引(简介,创建,删除)

如何在多列上创建索引

MySQL处理重复键错误插入具有多个唯一索引的表;不是多列唯一索引