Optionally creating or removing a column or table 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_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.
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
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