我运行了命令
rails g migration AddUser_idToComments User_id:string
然后我发现User_id应该是一个整数,所以我跑了
rails g migration AddUser_idToComments User_id:integer --force
认为它会覆盖初始命令。
但是现在,我收到了这个错误:
``` louismorin $ rake db:migrate == 20140910155248 AddIndexToComments:迁移=============================== - add_column(:comments,:Index,:string) - > 0.0069s == 20140910155248 AddIndexToComments:已迁移(0.0070s)======================
== 20140910181022 AddUserIdToComments:迁移============================== - add_column(:comments,:User_id,:integer) 耙子流产了! StandardError:发生错误,此以及所有后续迁移都已取消:
SQLite3 :: SQLException:重复的列名:User_id:ALTER TABLE“comments”ADD“User_id”integer / Users / louismorin / code / CP299 / db / migrate / 20140910181022_add_user_id_to_comments.rb:3:in change'
ActiveRecord::StatementInvalid: SQLite3::SQLException: duplicate column name: User_id: ALTER TABLE "comments" ADD "User_id" integer
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in
更改“
SQLite3 :: SQLException:重复的列名:User_id
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in`change'
任务:TOP => DB:迁移
(通过使用--trace运行任务查看完整跟踪)
```
这是我的schema.rb文件
``` ActiveRecord :: Schema.define(版本:20140910155210)做
create_table "comments", force: true do |t|
t.text "body"
t.integer "post_id"
t.datetime "created_at"
t.datetime "updated_at"
t.string "User_Id"
end
add_index "comments", ["post_id"], name: "index_comments_on_post_id"
create_table "posts", force: true do |t|
t.string "title"
t.text "body"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "user_id"
t.integer "topic_id"
end
add_index "posts", ["topic_id"], name: "index_posts_on_topic_id"
add_index "posts", ["user_id"], name: "index_posts_on_user_id"
create_table "topics", force: true do |t|
t.string "name"
t.boolean "public", default: true
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "users", force: true do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
t.string "role"
t.string "avatar"
t.string "Image"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
```
答案 0 :(得分:0)
由于该错误,您的第二次迁移 - 更改列类型 - 未运行。如果该迁移仅用于更改该列,则我们可以删除它生成的文件并重试。
如果您还没有关注该列中的任何数据,那就非常简单了:
rails g migration ChangeTypeOfUserIdOnComments
此迁移名称并不特殊。可能也是
DoWhateverIWant
然后,将创建的迁移的更改方法编辑为以下内容:
def change
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
end
当您运行未运行的迁移rake db:migrate
时,它不应该在错误的迁移(因为我们删除它),然后它应该运行这一个,这将删除列并添加它以正确的类型返回。
如果您想要保存数据,则过程会更复杂。您的更改方法必须获取每个注释的当前user_id,然后在创建新列时将它们分配给新注释。希望以下工作:
def change
user_ids = {}
Comment.find_each{ |c| user_ids[c.id] = c.user_id.to_i }
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
Comment.each{ |c| c.update_attribute(:user_id, user_ids[c.id])
end
另请注意,命令中的迁移名称通常都是CamelCase或所有snake_case。所以:AddColumnUserIdToComments
或add_column_user_id_to_comments
。如此命名可能会导致问题。
**编辑**
Modify a Column's Type in sqlite3
似乎SQLite没有很好的方法来修改/删除列。我建议:
删除表,删除原始user_id迁移以及新建的有关删除旧user_id列的行,然后使用新迁移创建新表。如果你不关心你的数据,应该可以正常工作
这可能是一个好主意(因为您希望您的生产和本地数据库的行为相同),但可能容易出错。
在这里寻求指导 - Change from SQLite to PostgreSQL in a fresh Rails project