Create or remove columns or tables with Rails migrations
Here's how to go about creating or removing a column optionally using Rails migrations
A feature that Rails 6.1 added was the ability to use :if_not_exists
and :if_exists
. This allow us to generate or remove a column or table if it was or wasn’t already present in the database.
It may seem strange that you would want to use methods like this. Surely a glance at your schema.rb
file would tell you what tables and columns you have in your database? While this is true sometimes your database can get in a state where the migration tables are out of sync because you’ve been switching branches frequently and are out of sync with other developers on your team. You may also be in the situation where you have had to restore from a database backup and it mightn’t be in sync with what you’re working with now.
Using :if_not_exists
This will create the Articles
table if it didn’t already exist in your system:
class CreateArticles < ActiveRecord::Migration[6.1]
def change
create_table :articles, if_not_exists: true do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
This will create the featured
column on the Discounts
table if it didn’t already exist:
class AddFeaturedToDiscounts < ActiveRecord::Migration[6.1]
def change
add_column :discounts, :featured, :boolean, default: false, if_not_exists: true
end
end
Using :if_exists
Conversely you can use :if_exists
when removing a column (or a table):
class RemoveSubtitleFromArticles < ActiveRecord::Migration[6.1]
def change
remove_column :articles, :subtitle, :text, if_exists: true
end
end
Before Rails 6.1
We would’ve had to use column_exists?
like so:
class RemoveSubtitleFromArticles < ActiveRecord::Migration[5.1]
def change
if ActiveRecord::Base.connection.column_exists?(:articles, :subtitle)
remove_column :articles, :subtitle
end
end
end
You can see how this is not as neat as the example given above.
Or to check for a table existing:
class DropArticles < ActiveRecord::Migration[5.1]
def change
if ActiveRecord::Base.connection.table_exists?(:articles)
drop_table :articles do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
end
This article is a part of the "Rails migrations" series
- Rails Migrations for Beginners
- How to change the column type with Rails migrate
- Removing fields with a Rails migration
- Running Rails migrations automatically on Heroku
- How to comment Rails migrations
- This Article
- Rails migrations - add default value to existing column
- What are the square brackets in my Rails migrations?
- What are Rails Migrations
- Forcing a Rails database column to be not null
- Irreversible Rails Migrations