使用预设ID为Rails数据库播种

bou*_*ard 2 mysql ruby-on-rails seed auto-increment

我有一个包含种子数据的XML文件,我正在尝试加载到我的生产数据库中.

问题是我在XML文件中的不同数据类型/节点之间存在关联,因此当从Rails加载到MySQL时,我需要指定的ID相同.

这在开发期间与SQLite一起工作正常,我只是在遍历XML文件中的每个节点后使用如下所示的行:

CardSet.connection.execute("UPDATE card_sets SET id = #{xml_set.attributes['id']} WHERE id = #{set.id}")
Run Code Online (Sandbox Code Playgroud)

我的问题是:如何在播种数据库时强制预先设置ID,然后能够重新启用auto_increment以使Rails正常运行?

在创建数据库条目之前,我已尝试使用这两行:

CardSet.connection.execute("ALTER TABLE card_sets CHANGE id id INT(11) DEFAULT NULL")
CardSet.connection.execute("ALTER TABLE card_sets DROP PRIMARY KEY")
Run Code Online (Sandbox Code Playgroud)

这之后:

CardSet.connection.execute("ALTER TABLE card_sets CHANGE id id INT(11) DEFAULT NULL auto_increment PRIMARY KEY")
Run Code Online (Sandbox Code Playgroud)

哪个MySQL反击给我:

Mysql::Error: ALTER TABLE causes auto_increment resequencing, resulting in duplicate entry '18' for key 'PRIMARY': ALTER TABLE card_sets CHANGE id id INT(11) DEFAULT NULL auto_increment PRIMARY KEY
Run Code Online (Sandbox Code Playgroud)

我的架构:

create_table "card_sets", :force => true do |t|
  t.string   "name"
  t.datetime "created_at"
  t.datetime "updated_at"
end

create_table "card_sets_cards", :id => false, :force => true do |t|
  t.integer "card_set_id"
  t.integer "card_id"
end

create_table "cards", :force => true do |t|
  t.text     "question",   :default => ""
  t.text     "answer",     :default => ""
  t.datetime "created_at"
  t.datetime "updated_at"
end
Run Code Online (Sandbox Code Playgroud)

和型号:

class CardSet < ActiveRecord::Base
  has_and_belongs_to_many :cards, :uniq => true
end

class Card < ActiveRecord::Base
    has_and_belongs_to_many :card_set, :uniq => true
end
Run Code Online (Sandbox Code Playgroud)

任何想法,将不胜感激.

bou*_*ard 5

我解决MySQL错误的方法是正常创建模型实例(CardSet.create),然后强制更新ID,然后重新加载实例:

c = CardSet.create(...blah....)
CardSet.connection.execute("UPDATE card_sets SET id = #{real_card_set_id} WHERE id = #{c.id}")
c = CardSet.find(real_card_set_id)
c.save!
Run Code Online (Sandbox Code Playgroud)