51

I found several similar questions about editing a migration but couldn't figure this one out. I did a rails migration, then opened the migration file and added a default value option to the field. Then ran rake db:migrate. The default value populates as intended. Then a few migrations later, I decided that I wanted to remove the default value option. How do I do that?

If this was the last migration I did, I would use db:rollback and recreate but since was done a few migrations ago, I'm not sure how to fix this.

Appreciate the help.

Moosa
  • 3,126
  • 5
  • 25
  • 45
  • 1
    This is where `version numbers` comes into play.Try `rake db:rollback:up VERSION=version_number_of_that_specific_migration_file` – Pavan Aug 18 '14 at 06:05
  • thanks! i didn't do the rollback but I removed the default value option from the migration file and it worked. Is that not the right way to edit a migration? – Moosa Aug 18 '14 at 06:10
  • 1
    you cant re-run a migration without first rolling it back. – sevenseacat Aug 18 '14 at 06:11
  • Got it. thanks. i thought it worked at first glance but you're right. I needed to rollback. – Moosa Aug 18 '14 at 06:22

2 Answers2

95

Create a new migration and use change_column_default.

http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_default

Sets a new default value for a column:

change_column_default(:suppliers, :qualification, 'new')
change_column_default(:accounts, :authorized, 1)

Setting the default to nil effectively drops the default:

change_column_default(:users, :email, nil)
sevenseacat
  • 24,699
  • 6
  • 63
  • 88
  • 1
    I can't get this to work. I ran `rails generate migraton change_column_default(:orders, :tracking, nil)` and I get this error sh.exe": syntax error near unexpected token `('. What am I missing here? – Moosa Aug 18 '14 at 16:53
  • So I removed the parentheses from the command and the migration ran but it generated an empty migration file with `def change end`. I ran rake db:migrate but as I thought, it didn't do anything. I still have the default value as in my previous migration. – Moosa Aug 18 '14 at 17:17
  • 4
    no, just generate a migration and call it something relevant like `change_default_on_suppliers_qualification`, and then edit the migration and add the `change_column_default` method. Not everything can be automatically generated for you. – sevenseacat Aug 19 '14 at 01:06
  • @sevenseacat This method is very useful. But on running this migration does this changes the value for existing records also? – Vishal Aug 22 '18 at 06:54
  • 2
    @Vishal no, it only changes the default value for newly inserted rows. Other rows will already have a value set. – sevenseacat Aug 22 '18 at 07:14
  • @sevenseacat thanks for such a quick reply. I got your point. So even if its value is nil its value wont be set, right? – Vishal Aug 22 '18 at 09:57
50

Rails 5+

Passing a hash containing :from and :to will make this change a reversible migration:

change_column_default(:posts, :state, from: nil, to: "draft")

Therefore I would recommend using this format where possible.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
Tom Lord
  • 27,404
  • 4
  • 50
  • 77
  • What version of Rails did this get added? With Rails 4 I'm getting `default: "---\n:from: ''\n:to: \n"` in my `schema.rb` and getting a `ActiveRecord::IrreversibleMigration` on a `db:rollback`. – Joshua Pinter Nov 30 '18 at 21:23
  • 1
    Answering my own question, it looks like it was added in Rails 5. I'll edit your answer to include that to avoid trouble for others running Rails 4 and 3. Here's the PR that added it: https://github.com/rails/rails/pull/20018/commits/a4128725f5a2c6cbf3e963e2b78ba9382732728a – Joshua Pinter Nov 30 '18 at 21:34
  • 1
    Thanks @JoshuaPinter, I must have missed that it was a recent addition when answering. In order to make this migration reversible in *older* rails versions, you could explicitly define `up` and `down` methods in the migration, rather than a single `change` method. – Tom Lord Dec 02 '18 at 11:05
  • That's right. Old school way. What's troubling is that Rails doesn't throw an error. Instead, it plops some serialized junk for the `default` value. – Joshua Pinter Dec 03 '18 at 01:00
  • I've found that rolling back doesn't remove the default when using `from: nil, to: 'somedefault'`. I had to use reversible to specify that the rollback use `change_column_default(:some_things, :some_column, nil)`. Note: I'm using postgres. – cesoid Sep 24 '21 at 18:04