我试图将表格<tag><innertag>some value</innertag></tag>
字段更改为id
这是我的代码:
uuid
由于外键约束,尝试class AddUuidToProjects < ActiveRecord::Migration[5.0]
def up
add_column :projects, :uuid, :string, limit:36, null: false, first: true
add_column :projects, :old_id, :integer
Project.all.each do |p|
p.update!(old_id: p.id)
end
change_table :projects do |t|
t.remove :id
t.rename :uuid, :id
end
execute "ALTER TABLE projects ADD PRIMARY KEY (id);"
Project.all.each do |p|
# has_one image
Image.find(p.old_id).update!(project: p)
# has_many stories
Story.where(project_id: p.old_id).each do |s|
s.update!(project: p)
end
end
end
...
end
时此迁移会中断。错误消息是:
t.remove :id
问题是,如果整个迁移运行,那么我将用另一个列交换Mysql2::Error: Cannot drop column 'id': needed in a foreign key constraint 'fk_rails_be41fd4bb7' of table 'db_dev.stories': ALTER TABLE `projects` DROP `id`
列,并修复外键。那么,有没有办法忽略迁移的约束?
答案 0 :(得分:2)
class ClipBoardCopier extends StatelessWidget {
@override
Widget build(BuildContext context) {
List<String> data = ['Hello', 'Flutter'];
return ListView.builder(
itemCount: data.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
title: Text('ListTile #$index'),
onTap: (){
Clipboard.setData(ClipboardData(text: data[index]));
},
);
},
);
}
}
(Github)。至少需要Rails 4.2。
P.S。
我发现上面的代码很容易出错。对我而言,主要原因是缺乏针对此类关键任务的测试。来自“ Thoughtbot”的article很棒,涉及将数据迁移与结构迁移混合在一起的其他问题。
我会考虑创建单独的数据迁移(当然会包含测试)。 Example。
答案 1 :(得分:1)
我的最终代码
if
和unless
语句是因为我正在逐步编写和测试(失败的迁移仍然会产生持久影响)。最重要的是删除外键然后将它们添加回去(删除键不会删除数据库中的id
字段,只删除约束。
class AddUuidToProjects < ActiveRecord::Migration[5.0]
def up
# remove constraint
if foreign_key_exists?(:stories, :projects)
say("removing foreign key constraints")
remove_foreign_key "stories", "projects"
remove_foreign_key "images", "projects"
end
# create UUID id column
unless column_exists?(:projects, :id, :string)
say("adding UUID column")
add_column :projects, :uuid, :string, limit:36, null: false, first: true
add_column :projects, :old_id, :integer
Project.all.each do |p|
p.update!(old_id: p.id, uuid: SecureRandom.uuid)
end
change_table :projects do |t|
t.remove :id
t.rename :uuid, :id
end
execute "ALTER TABLE projects ADD PRIMARY KEY (id);"
end
# update foreign keys
if(Image.first.project_id.is_a? Integer)
say("updating foreign keys")
# change foreign key fields to STRING(36)
change_column :images, :project_id, :string, limit:36, null: false
change_column :stories, :project_id, :string, limit:36, null: false
Project.all.each do |p|
# has_one soi
Image.find_by(project: p.old_id).update!(project: p)
# has_many stories
Snippet.where(project_id: p.old_id).each do |s|
s.update!(project: p)
end
end
end
# add constraints back
unless foreign_key_exists?(:stories, :projects)
say("adding foreign key constraints back")
add_foreign_key "stories", "projects"
add_foreign_key "images", "projects"
end
end
答案 2 :(得分:0)
在mysql上,您可以这样做:
begin
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=0;'
# Your statements
...
ensure
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=1;'
end
答案 3 :(得分:0)
如果您混合使用mysql-sqlite环境,则可以执行以下操作:
class AddUuidToProjects < ActiveRecord::Migration[5.0]
def up
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=0;' if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
# Your code
# ...
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=1;' if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
end
def down
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=0;' if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
# Your code
# ...
ActiveRecord::Base.connection.execute 'SET FOREIGN_KEY_CHECKS=1;' if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
end
end