3

I have the following migration. Is there a way to run these changes in one change than 3?

def change
 change_column :comments, :attr_1, :string, null: true
 change_column :comments, :attr_2, :string, null: true
 change_column :comments, :attr_3, :string, null: true
end
mikeymurph77
  • 752
  • 1
  • 11
  • 28
  • 1
    Just curious, why are you concerned about running three migrations? This kind of thing is perfectly normal for a Rails app. – NM Pennypacker Sep 20 '16 at 18:17
  • I know this comment is super old, but in case anyone comes back here. For me, I had a really large table and I needed to change multiple columns, which would force a reindex and table lock for each statement. Though I was okay with some downtime during the change, 3x the downtime isn't practical. Unfortunately, there isn't a solution to this with ALTER TABLE: https://stackoverflow.com/questions/3465560/how-to-alter-multiple-columns-at-once-in-sql-server/17480817 – Michael Oct 06 '19 at 04:14

2 Answers2

9

The short answer is no. The change_column method is configured to take arguments for table name, column name, and an options hash. The source code for change_column can be found here: https://github.com/rails/rails/blob/0fe76197d2622674e1796a9a000995a7a1f6622b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb

The only line in the change_column method is: execute("ALTER TABLE #{quote_table_name(table_name)} #{change_column_sql(table_name, column_name, type, options)}")

which executes an ALTER script on the table name passed as the first argument. You can't pass an array of tables/columns as arguments, so you have to do them one at a time. This paradigm is fairly typical in Rails migrations.

NM Pennypacker
  • 6,704
  • 11
  • 36
  • 38
2

You can use the change_table function with bulk set to true which will run the alter as a single MySQL query and be much faster than running individually. Example is below.

def change
 change_table(:comments, bulk: true) do |t|
  t.change :attr_1, :string, null: true
  t.change :attr_2, :string, null: true
  t.change :attr_3, :string, null: true
 end
end
Kavan
  • 41
  • 1
  • 4