DEV Community

Cover image for Migrations and Changes
aiodell
aiodell

Posted on

Migrations and Changes

Migrations are just a small part of what Active Record is capable of. Once you get used to how migrations work, your speed in creating these migrations will increase and become muscle memory like all the other lines of code you have created within Ruby.


Creating a Migration

In order to create a migration, we need to enter code that looks like this:

bundle exec rake db:create_migration NAME=create_my_friends_table

If done correctly, this should have appeared in the terminal:

db/migrate/20220822163630_create_my_friends_table.rb

bundle exec is used to ensure that there are no compatibility issues between versions. It is a safer practice to use bundle exec even if you are certain your version is working.

After migrating, you create your table like so:

create table

You add your migration to the database with bundle exec rake db:migrate. It will give you another message that states that the migration was successful. If you did it correctly, you should have seen a message appear showing that the migration was added into the db folder.

migration success

After the migration, you should be able to see that a schema has been created for you within the same db directory and can be viewed. You can check the status of your migration with bundle exec db:migrate:status. It will show you which migrations status on whether they are active or not.

migration up status

There are numbers found in the name of the migration that should not be changed or else you will receive errors. They identify that specific migration and also logs when that migration is made. It becomes useful when working with multiple people who need to trace back to a certain migration.


Making Changes After Running the Migration

Rolling back

If you migrated your table, but realized you need to make a change, you can rollback to the previous migration with bundle exec rake db:rollback. This will change the status from up to down and enable you to make a change. If there were multiple migrations, the most recent one would be removed.

rollback example

In this case, I did not feel the need to have whether or not I have been talking to my friends. I also decided that there was no need to think about the years of friendship and wanted to add age instead.

updated table

When migrating again, we will be able to see the changes go through under the same migration name. The schema also shows this change.

new schema

**Note: **If you wanted to rollback multiple migrations, you could use bundle exec db:rollback STEP=<number of migrations back>


Migration methods

Active Record was kind enough to provide us with methods to make changes to our database without needed to completely drop our table and start over again. Here are a list of a few of them:

  • add_column
  • add_index
  • change_column
  • change_table
  • create_table
  • remove_column
  • remove_index
  • rename_column

We already have seen create_table when we created our table. I will not go over all of them here in detail, but I want you to be aware of the others that exist. For every example, there will be a new migration. Personally, I like being able to create migrations because I want to keep track of all changes I made to my database. I would rather rollback to a previous migration than have to redo an entire table

Adding Columns

If I wanted to add a column to my current migration without rolling back, I would go through the process of creating a new migration, and name that migration based on what I was doing. Therefore, it would be bundle exec rake db:create_migration NAME=add_phone_number_to_friends_table

After that, the syntax within the migration will be different because we are adding a column. It will be add_column :table_name, :column_name, :data_type. Naming the migration after the table that is being changed helps with organization. I would not want to open up migrations to see where the name of the table appears.

adding column

Once you run the migration, it will be updated in the schema and should be placed as the last column.

Removing Columns

If my friends were upset that I placed their age (they would never be they are happy I remember their age but this is just a scenario), I would create another migration to remove the column. I'm sure we know the process of creating migrations for now, so I will show the syntax for removing a column remove_column :table_name, :column_name

remove_column syntax

If things have been working out for you, the schema will look something like this:

updated schema without age and with phone number

Changing Columns

Even more changes need to be made! We realized we don't want an integer for our phone number, we want a string! We need to once again (and I promise this is the last migration) create a new migration. At least you now are an expert at creating these things! The syntax for this is just as simple as removing and adding columns. change_column :table_name, :column_name, :new_data_type

change columns

The final schema should look like this:

final schema

If you noticed, the methods all began the same way: identifying the table. This is because without identifying a table, it would not know what table you are looking at. Just because the name of the migration is supposedly linked to the table you are making changes to, it does not mean you are automatically linking the table to the migration. A name is just a name.

Just Drop It

There might be cases where a migration made something irreversible. For instance, you might have destroyed data that no longer can be retrieved, you can always drop the table with bundle exec rake db:drop to drop the entire database and run migrations all over again to the version you desire. However this might become troublesome with larger databases and is probably best to be avoided if possible.


Note on the other methods:

remove_index will remove the given index from the table

add_index will add a new index to the table. Unless you specify, the index will be named after the table and the column name or names (if you added multiple columns each name would be included)

The rename_column method is in a similar format as change column, but where the datatype is located at is now replaced with the new column name: rename_column :table_name, :column_old_name, :column_new_name

change_table creates a block to change columns in a table like so:

change table example


Resources:

apidock.com

Migrations

Top comments (3)

Collapse
 
lucianghinda profile image
Lucian Ghinda

In case the article talks about using ActiveRecord in Rails 7 I suggest some small changes:

Replace

bundle exec rake db:create_migration NAME=create_my_friends_table

with

bundle exec rails generate migration CreateMyFriendsTable

Where CreateMyFriendsTable is the name of the migration class.
See the latest Rails Guides: guides.rubyonrails.org/active_reco...


Replace:

bundle exec rake db:migrate

with

bundle exec rails db:migrate

And in general you can replace rake with rails in all these db-related commands.


Also, I see that the documentation you added at the end Migrations points to documentation for Rails v3.2 but I see in the screenshots (the one with the migration file) that you are running at least Rails 6.1 so I suggest to link to a more up to date documentation.

Collapse
 
nezirzahirovic profile image
Nezir Zahirovic

also can write bit shorter:
bundle exec rails g migration CreateMyFriendsTable

and also, not sure why do you use all the time bundle exec something is wrong in your project if you need to use it all the time.

So, I would mostly use just:
rails g migration CreateMyFriendsTable

Collapse
 
aiodell profile image
aiodell

Thank you! This was before I was introduced to rails so I was working with what I had. I'm now using rails generate and am loving it!