ChatGPT解决这个技术问题 Extra ChatGPT

Add a default value to a column through a migration

How do I add a default value to a column that already exists through a migration?

All the documentation I can find shows you how to do it if the column doesn't already exist but in this case it does.


M
Maurício Linhares

Here's how you should do it:

change_column :users, :admin, :boolean, :default => false

But some databases, like PostgreSQL, will not update the field for rows previously created, so make sure you update the field manaully on the migration too.


If you need reversible migrations, put this in an up block rather than a change block. You can leave the down block empty. It won't revert the table to the original condition but the migration can be rolled back.
Will this keep the data intact?
On PostgreSQL, yes, I don't know what will happen on other databases.
I tried it on PostgreSQL and it updated previously created fields.
@AboozarRajabi I just tried it on PostgreSQL and it didn't update previously created fields.
S
Soviut
change_column_default :employees, :foreign, false

@DenisLins I agreed with you, so I did some research to figure out why it might not be, and it turns out there's a possibility that a particular database adapter doesn't support it, as it's implemented at that level. The accepted answer is still the safest bet until it's implemented in the abstract model. apidock.com/rails/ActiveRecord/ConnectionAdapters/…
Besides that, you need to specify a from: and to: if you want it to be reversible :)
Using from and to was added in Rails 5+ in this commit: github.com/rails/rails/pull/20018/files
d
davegson

For Rails 4+, use change_column_default

def change
  change_column_default :table, :column, value
end

This is great especially if you have a migration that is adding a column and setting defaults for existing records. For example: def change ` add_column :foos, :name, default: "something for existing values"` ` change_column_default :foos, :name, default: ""` end
This migration have a strange behaviour. In yours example it's irreversible. edgeguides.rubyonrails.org/active_record_migrations.html recommend to use it this way: change_column_default :products, :approved, from: true, to: false — but it doesn't works too.
can't rollback using that?
Usually so yes, for almost any "Change" clause, since all previous states are usually explicit, such as the presence of a column, it's type, etc. The change can be rolled back as it's shown there if and only if there was a valid explicit default previously. Since it's common that defaults are undefined, you might have an issue there.
b
bfcoder

Using def change means you should write migrations that are reversible. And change_column is not reversible. You can go up but you cannot go down, since change_column is irreversible.

Instead, though it may be a couple extra lines, you should use def up and def down

So if you have a column with no default value, then you should do this to add a default value.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

Or if you want to change the default value for an existing column.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end

J
James Bush

**Rails 4.X +**

As of Rails 4 you can't generate a migration to add a column to a table with a default value, The following steps add a new column to an existing table with default value true or false.

1. Run the migration from command line to add the new column

$ rails generate migration add_columnname_to_tablename columnname:boolean

The above command will add a new column in your table.

2. Set the new column value to TRUE/FALSE by editing the new migration file created.

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

**3. To make the changes into your application database table, run the following command in terminal**

$ rake db:migrate

How is this any different to rails 3+ or 2+?
Does anyone know if this has been incorporated into Rails 5?
@sambecker I know I might be a little late replying to your comment, but it's working for me on Rails 6.0.3.1
@Mathyou good to know. In Rails 6 can a new table have columns with default values? Or is still a separate migration?
@sambecker you can definitely set default values in the new table migration. One of my columns in such a migration looks like: t.boolean :is_active, :null => false, :default => false
a
axeltaglia

Execute:

rails generate migration add_column_to_table column:boolean

It will generate this migration:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

Set the default value adding :default => 1

add_column :table, :column, :boolean, :default => 1

Run:

rake db:migrate


Now the default value of 1 is not exactly a boolean ;) Also, this exampe adds a new column, instead of changing the existing column, which is what the OP wanted to achieve
@radiospiel Actually, 1 is a boolean too :)
You will also need to create a record in the foreign key table with an ID of 1 for this to work, to avoid the Key is not present in table error.
r
rmcsharry

This is what you can do:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

EDIT: ...but apparently this is a Rookie mistake!


It's better if you set the default in the schema vs as a before_save
What a terrible suggestion
agreed, it's really terrible
ouch, you got a lot of heat for doing something at model level instead of database level. -38 is a legendary score.
what a rookie mistake... ;-)