Rails Migrations: Check Existence and Keep Going?

Ruby on-RailsMigration

Ruby on-Rails Problem Overview


I was doing this kind of thing in my migrations:

add_column :statuses, :hold_reason, :string rescue puts "column already added"

but it turns out that, while this works for SQLite, it does not work for PostgreSQL. It seems like if the add_column blows up, even if the Exception is caught, the transaction is dead and so the Migration can't do any additional work.

Is there any non-DB sepecific ways to check if a column or table already exist? Failing that, is there any way to get my rescue block to really work?

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

As of Rails 3.0 and later, you can use column_exists? to check for the existance of a column.

unless column_exists? :statuses, :hold_reason
  add_column :statuses, :hold_reason, :string
end

There's also a table_exists? function, which goes as far back as Rails 2.1.

Solution 2 - Ruby on-Rails

Or even shorter

add_column :statuses, :hold_reason, :string unless column_exists? :statuses, :hold_reason

Solution 3 - Ruby on-Rails

Rails 6.1+:

add_column :statuses, :hold_reason, :string, if_not_exists: true

https://github.com/rails/rails/pull/38352/files

Rails < 6.1:

add_column :statuses, :hold_reason, :string unless column_exists?(:statuses, :hold_reason)

Solution 4 - Ruby on-Rails

For Rails 2.X, you can check the existence of columns with the following:

columns("[table-name]").index {|col| col.name == "[column-name]"}

If it returns nil, no such column exists. If it returns a Fixnum, then the column does exist. Naturally, you can put more selective parameters between the {...} if you want to identify a column by more than just its name, for example:

{ |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil }

(this answer first posted on https://stackoverflow.com/questions/4980895/how-to-write-conditional-migrations-in-rails/9912032#9912032)

Solution 5 - Ruby on-Rails

add_column :statuses, :hold_reason, :string unless Status.column_names.include?("hold_reason")

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDan RosenstarkView Question on Stackoverflow
Solution 1 - Ruby on-RailsTobias CohenView Answer on Stackoverflow
Solution 2 - Ruby on-RailsSG 86View Answer on Stackoverflow
Solution 3 - Ruby on-RailsRadin RethView Answer on Stackoverflow
Solution 4 - Ruby on-RailsJellicleCatView Answer on Stackoverflow
Solution 5 - Ruby on-RailsDenis NeverovView Answer on Stackoverflow