ChatGPT解决这个技术问题 Extra ChatGPT

Rails migration for change column

We have script/generate migration add_fieldname_to_tablename fieldname:datatype syntax for adding new columns to a model.

On the same line, do we have a script/generate for changing the datatype of a column? Or should I write SQL directly into my vanilla migration?

I want to change a column from datetime to date.


N
Nikita Fedyashev

Use #change_column.

change_column(:table_name, :column_name, :date)

# a few more examples:
change_column(:suppliers, :name, :string, limit: 80)
change_column(:accounts, :description, :text)

NOTE: the same result can be achieved even outside of db migrations, this might be handy for testing/debugging but this method needs to be used very cautiously:

ActiveRecord::Base.connection.change_column(:table_name, :column_name, :date)

@b_ayan: as far as I know, the only magical words in migration names are "add" and "remove".
Sort-of rails noob here, but … I understand the answer but not the comments on this answer. Clarifications appreciated :)
When you create a migration, you give it a name (e.g. add_fieldname_to_tablename in the question above). If it starts with "add" or "remove" then the migration will be automatically populated with code to add or remove columns, which saves you writing that code yourself.
It's also worth bearing in mind you should replace the usual change action with separate up and down actions, as change_column is an irreversible migration and will raise an error should you need to roll back.
@QPaysTaxes up should contain what you want to change your column from and to, and down should contain how to reverse that change.
s
shilovk

You can also use a block if you have multiple columns to change within a table.

Example:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

See the API documentation on the Table class for more details.


R
Ryan

I'm not aware if you can create a migration from the command line to do all this, but you can create a new migration, then edit the migration to perform this taks.

If tablename is the name of your table, fieldname is the name of your field and you want to change from a datetime to date, you can write a migration to do this.

You can create a new migration with:

rails g migration change_data_type_for_fieldname

Then edit the migration to use change_table:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Then run the migration:

rake db:migrate

A
Aboozar Rajabi

As I found by the previous answers, three steps are needed to change the type of a column:

Step 1:

Generate a new migration file using this code:

rails g migration sample_name_change_column_type

Step 2:

Go to /db/migrate folder and edit the migration file you made. There are two different solutions.

def change change_column(:table_name, :column_name, :new_type) end

2.

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Step 3:

Don't forget to do this command:

rake db:migrate

I have tested this solution for Rails 4 and it works well.


In step 2, the first will fail after running rake db:rollback, I recommend you check the second
Is there a rails convention that allows everything to be more or less done when generating the migration file without going to it, and then editing it?
@BKSpurgeon Yes, check the documentation here: edgeguides.rubyonrails.org/active_record_migrations.html
M
Mr. Tao

With Rails 5

From Rails Guides:

If you wish for a migration to do something that Active Record doesn’t know how to reverse, you can use reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end

J
Joshua Pinter

Just generate migration:

rails g migration change_column_to_new_from_table_name

Update migration like this:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

and finally

rake db:migrate

S
Sebastian Scholl

This is all assuming that the datatype of the column has an implicit conversion for any existing data. I've run into several situations where the existing data, let's say a String can be implicitly converted into the new datatype, let's say Date.

In this situation, it's helpful to know you can create migrations with data conversions. Personally, I like putting these in my model file, and then removing them after all database schemas have been migrated and are stable.

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end

S
Sachin Singh

You can use change_column for this:

def change
  change_column :table_name, :column_name, :new_data_type
end

Only issue here is that it's not reverseable. Use def up instead and implement def down.
P
Prasanth_Rubyist

Another way to change data type using migration

step1: You need to remove the faulted data type field name using migration

ex:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Here don't forget to specify data type for your field

Step 2: Now you can add field with correct data type

ex:

rails g migration AddFieldNameToTableName field_name:data_type

That's it, now your table will added with correct data type field, Happy ruby coding!!


Worth noting here that all data in that column will be lost with this method.
Yeah, offcourse if you have data in that column, you add the column first then pull the data from the existing column
Not everyone is on the same level of coding. So it's not obvious to everyone, especially beginners. Since this SO question was about changing the column type and not re-creating it, I think it's a valid warning to put out.
G
Gregdebrick

To complete answers in case of editing default value :

In your rails console :

rails g migration MigrationName

In the migration :

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Will look like :

  def change
    change_column :members, :approved, :boolean, default: true
  end