Reputation: 149
I ran the command
rails g migration AddUser_idToComments User_id:string
and then I figured out that User_id should be an integer and so I ran
rails g migration AddUser_idToComments User_id:integer --force
thinking that it would overwrite the initial command.
But now, I'm getting this error:
``` louismorin$ rake db:migrate == 20140910155248 AddIndexToComments: migrating =============================== -- add_column(:comments, :Index, :string) -> 0.0069s == 20140910155248 AddIndexToComments: migrated (0.0070s) ======================
== 20140910181022 AddUserIdToComments: migrating ============================== -- add_column(:comments, :User_id, :integer) rake aborted! StandardError: An error has occurred, this and all later migrations canceled:
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 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
change'
SQLite3::SQLException: duplicate column name: User_id
/Users/louismorin/code/CP299/db/migrate/20140910181022_add_user_id_to_comments.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
```
Here's my schema.rb file
``` ActiveRecord::Schema.define(version: 20140910155210) do
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
```
Upvotes: 1
Views: 3213
Reputation: 6466
Because of the error, your second migration -- changing the column type -- didn't run. If that migration was only intended to change that one column, we could then delete the file it generated and try again.
If you don't yet have any data in that column that you care about, that's pretty easy:
rails g migration ChangeTypeOfUserIdOnComments
This migration name isn't special. Might as well have been
DoWhateverIWant
Then, edit the created migration's change method to something like this:
def change
remove_column :comments, :user_id
add_column :comments, :user_id, :integer
add_index :comments, :user_id
end
When you then run your un-run migrations rake db:migrate
, it shouldn't trip up on the one which errored (because we deleted it), and then it should run this one, which removes the column and adds it back with the correct type.
If you DO have data you want to save, the procedure is more complicated. Your change method would have to grab the current user_id's for each comment, and then assign them to the new comments when we create the new column. The below should hopefully work:
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
Also note that the names of the migration in the command are generally all CamelCase or all snake_case. So: AddColumnUserIdToComments
or add_column_user_id_to_comments
. Naming as you did might cause problems.
** EDIT **
Modify a Column's Type in sqlite3
It appears that SQLite has NO good way to modify/drop a column. I'd suggest either:
Drop the table, drop the original user_id migration and the line in the new one about removing the old user_id column, and then create a new table with the new migrations. Should work fine if you don't care about your data
It's probably a good idea (because you want your production and local databases to behave identically), but can be bug-prone to switch to.
Look here for guidance -- Change from SQLite to PostgreSQL in a fresh Rails project
Upvotes: 0