191

I have the problem, that I have an migration in Rails that sets up a default setting for a column, like this example:

def self.up
  add_column :column_name, :bought_at, :datetime, :default => Time.now
end

Suppose, I like to drop that default settings in a later migration, how do I do that with using rails migrations?

My current workaround is the execution of a custom sql command in the rails migration, like this:

def self.up
  execute 'alter table column_name alter bought_at drop default'
end

But I don't like this approach, because I am now dependent on how the underlying database is interpreting this command. In case of a change of the database this query perhaps might not work anymore and the migration would be broken. So, is there a way to express the undo of a default setting for a column in rails?

Kara
  • 6,115
  • 16
  • 50
  • 57
wulfovitch
  • 3,216
  • 2
  • 24
  • 15

4 Answers4

388

Rails 5+

def change
  change_column_default( :table_name, :column_name, from: nil, to: false )
end

Rails 3 and Rails 4

def up
  change_column_default( :table_name, :column_name, nil )
end

def down
  change_column_default( :table_name, :column_name, false )
end
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
Jeremy Mack
  • 4,987
  • 2
  • 25
  • 22
  • 7
    In postgres, this won't actually drop the default for `CHARACTER VARYING` columns, just set it to `NULL::character varying`. – Attila O. Oct 27 '14 at 10:36
  • 8
    In more recent versions, you can make it reversible. For example: `change_column_default(:table_name, :column_name, from: nil, to: false)` – Mark Feb 23 '17 at 19:17
  • 2
    @AttilaO. I've had success running `ALTER TABLE table_name ALTER COLUMN type DROP DEFAULT`, no need to set it to `NULL` I think. – Eli Rose Apr 27 '17 at 20:00
  • FYI, it looks like the reversible version that @Mark mentions was added in Rails 5+, so anything below that, you won't be able to use it. – Joshua Pinter Nov 07 '18 at 23:42
23

Sounds like you're doing the right thing with your 'execute', as the docs point out:

change_column_default(table_name, column_name, default)

Sets a new default value for a column. If you want to set the default value to NULL, you are out of luck. You need to DatabaseStatements#execute the appropriate SQL statement yourself. Examples

change_column_default(:suppliers, :qualification, 'new')
change_column_default(:accounts, :authorized, 1)
Serx
  • 1,358
  • 8
  • 14
  • Thanks! I haven't found this hint in the docs by myself! Hopefull they build in the dropping of default values into migrations in future versions of rails. – wulfovitch May 20 '09 at 12:33
  • 1
    This is not true anymore as of Rails 3.1.0, cfr. http://apidock.com/rails/v3.1.0/ActiveRecord/ConnectionAdapters/SchemaStatements/change_column_default – asymmetric Jun 25 '13 at 12:28
14

The following snippet I use to make NULL columns NOT NULL, but skip DEFAULT at schema level:

def self.up
  change_column :table, :column, :string, :null => false, :default => ""
  change_column_default(:table, :column, nil)
end
Alex Fortuna
  • 1,223
  • 12
  • 16
-3

Rails 4

change_column :courses, :name, :string, limit: 100, null: false
Pardeep Dhingra
  • 3,916
  • 7
  • 30
  • 56
Lesly Revenge
  • 894
  • 10
  • 16