无法在 Rails 3.2 中使用复合唯一索引将记录添加到连接表
Posted
技术标签:
【中文标题】无法在 Rails 3.2 中使用复合唯一索引将记录添加到连接表【英文标题】:Can't add record to join table with composite unique index in Rails 3.2 【发布时间】:2013-03-02 15:09:46 【问题描述】:重要 - 阅读下面的编辑以获取有关问题的更新
当我尝试将新记录添加到 SQLite3 上具有唯一复合键索引的连接表时,我得到了我认为的虚假错误。请注意,对于我所做的所有(手动)测试,数据库已通过 db:drop 后跟 db:migrate 完全重建。
错误:
ActiveRecord::RecordNotUnique
SQLite3::ConstraintException: columns adventurer_id, item_id are not unique:
INSERT INTO "adventurers_items" ("adventurer_id", "item_id") VALUES (1, 68)
产生错误的代码:
class Adventurer < ActiveRecord::Base
after_create :set_starting_skills
after_create :set_starting_items
has_and_belongs_to_many :items
has_and_belongs_to_many :skills
# automatically add starting skills on creation
def set_starting_skills
self.skills = self.profession.starting_skills
end
# automatically add starting items on creation
def set_starting_items
self.items = self.profession.items
end
创建连接表 Adventurers_skills 的迁移:
class AdventurersItems < ActiveRecord::Migration
def change
create_table :adventurers_items do |t|
t.integer :item_id, :null => false
t.integer :adventurer_id, :null => false
end
add_index :adventurers_items, :item_id
add_index :adventurers_items, :adventurer_id
add_index :adventurers_items, [:adventurer_id, :item_id], :unique => true
该表存在并且完全为空。为什么我的应用程序由于唯一性约束而无法插入此记录?我对等效表“adventurers_skills”也有同样的错误——我在架构上做错了吗?
编辑
系统正在尝试添加相同的物品/技能两次。当我将私有方法更改为此:
def set_starting_skills
skills = profession.starting_skills
end
它不会尝试在连接表中创建任何内容。但是将第一行恢复为 self.skills 如下尝试创建相同的技能 TWICE
def set_starting_skills
self.skills = profession.starting_skills
end
返回
(0.4ms) INSERT INTO "adventurers_skills" ("adventurer_id", "skill_id") VALUES (4, 54)
(4.9ms) INSERT INTO "adventurers_skills" ("adventurer_id", "skill_id") VALUES (4, 54)
SQLite3::ConstraintException: columns adventurer_id, skill_id are not unique:
INSERT INTO "adventurers_skills" ("adventurer_id", "skill_id") VALUES (4, 54)
(3.2ms) rollback transaction
profession.starting_skills
只返回一项技能:
1.9.3-p194 :022 > Profession.find(7).starting_skills.each |x| puts x.id
54
所以真正的问题变成了:为什么 Rails 会尝试两次添加这个 HABTM 记录?
【问题讨论】:
请向我们展示导致该错误的代码。模型和迁移实际上并没有插入数据。不过,还有别的东西。所以请向我们展示“其他东西” 嗯,有一个错误在某处调用了两次回调方法,因此它试图插入一个项目两次。 那么,您解决了这个问题吗?因为我得到的完全一样。 【参考方案1】:您需要将回调声明 (after_create :set_starting_skills
) 放在 关系声明 (has_and_belongs_to_many :skills
) 之后。
即模型中线的顺序很重要,否则会出现此错误。
这太疯狂了,还有a GitHub issue for it。
【讨论】:
以上是关于无法在 Rails 3.2 中使用复合唯一索引将记录添加到连接表的主要内容,如果未能解决你的问题,请参考以下文章
MongoDB——索引属性之唯一索引(Unique Indexes)