2

重要 - 阅读下面的编辑以获取有关问题的更新

当我尝试将新记录添加到 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 记录?

4

1 回答 1

0

您需要将回调声明 ( after_create :set_starting_skills)放在关系声明 ( )之后has_and_belongs_to_many :skills

即模型中线的顺序很重要,否则你会得到这个错误。

这太疯狂了,它有一个 GitHub 问题

于 2013-07-19T20:54:25.427 回答