由于多列上的唯一索引,无法更新 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 中有一个 Race
和 id:1
和两个 Drivers
和 id: 1, order:1
和 id: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 中使用复合唯一索引将记录添加到连接表