Migrations and Changes
Tags: todayilearned, beginners, ruby, codenewbie
Published: 2022-08-23 01:44:00

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kwlrpo8v95xl6z1igvgz.png)
  
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vg3bv5pcg2fc5lxlavw8.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qq5be2diurq3n8h0coks.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f2nustmz2ir6c0f29ipy.png)
 
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kfsix324cma3qeotu25b.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hpkrac5nfwixixrhen3c.png)

**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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/et41so1dk99953anhv34.png)
 
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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wkq26mwkr6xlpvbzbzlf.png)
 
If things have been working out for you, the schema will look something like this:

![updated schema without age and with phone number](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryatejxqwodj0sedl6l4.png)
 
**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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cv4w2mtboqsm42mdu8qg.png)
 
The final schema should look like this:

![final schema](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/somlq8v3g0wuuu2e7jwp.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s12ih7jrs6gc6t6ra3t8.png
)

---
Resources:

[apidock.com](https://apidock.com/rails/v4.0.2/ActiveRecord/ConnectionAdapters/SchemaStatements/add_index)

[Migrations](https://guides.rubyonrails.org/v3.2/migrations.html)