Rails Migration — Part 1
Generating migration files.
Prerequisite:
Table of Contents
↦ Migration File
↪ Name format
↪ create_table
↪ references
↪ comment
Definition
Migration is one of the features of Active Record which enables us to modify our table in database in a structured and organized manner.
As I covered in the Active Record article, migrations allow us to modify or create the transformations of a database in Ruby, which means we don't have to worry about implementing SQL for the most part, however, for certain database features, we would require to use SQL.
This topic is very vast to be covered in a single article. So I have divided it into 3 parts, in this article (Part 1) we will cover:
- How to generate tables and declare their attributes with the custom data type.
- Understanding migration files.
- Methods like
create_table
and special helpers liketimestamp
andreferences
. unique
andindex
keys.- Destroy migration.
Part 2: Executing Migration Files
Part 3: Update Existing Tables
Migration File
To generate a table named authors
with name
and age
as its attribute in the database, we give a migration like this in CMD:
rails generate model Author name:string age:integer
This is called a model generator and contains instructions for creating a relevant table. We specify the name of a table we want to create and attributes of it along with its data type.
After running the following command, we get the following output:
invoke active_record
create db/migrate/20210721030949_create_authors.rb
create app/models/author.rb
invoke test_unit
create test/models/author_test.rb
create test/fixtures/authors.yml
It has created 4 files for us:
- Migration file 👉
migrate/20210721030949_create_authors.rb
- Corresponding model file 👉
app/models/author.rb
- The other 2 files are corresponding test files of
authors
table.
Migration File Name Format
The above command invoked Active Record to run the migration and created a migration file automatically in db/migrate
directory in this format : YYYYMMDDHHMMSS_migration_name.rb
.
The YYYYMMDDHHMMSS
represents a UTC of when migration was generated followed by an underscore followed by migration name, create_authors
.
The migration file name will always be in the format of snake_case whereas the table name will be in CamelCase, So for the table name Author
, its corresponding file will be create_author
, for Product
, its corresponding file will be create_product
and so on.
A look at the migration file:
The CreateAuthors
class has been generated for us which inherits from the Migration
class of the ActiveRecord
module. This means we have all of the instance methods available to use from theMigration
class.
create_table
In the scope of change
method, the create_table
method takes 2 arguments, first, the name of the table in the database, authors
and second, takes a block of attributes and its data-type as key:value
pairs. The t.timestamps
method is implicitly added by Active Record which will generate 2 columns, created_at
and updated_at
along with the primary key, id
.
references
A foreign key is an attribute in a table where for each of its intsances it links to a row of another table.
These are used in a table whose in a relationship with another table so that each instance of it can link to anyone instance of the other table with its primary key. We need to explicitly define it as it isn’t declared for us implicitly.
Let's see an example of references
We create another table books
so that each book is linked to an author from the authors
table.
rails g model Book title:string author:references
g
is short for generate
. With references
given to the table of authors
, this will create a column or an attribute :
- with a name formatted as
‘table_name’_id
, in our caseauthors_id
- which is our
foreign_key
.
For this reason,
references
method is also called a special helper method because it provides a simple shortcut to multiple functionality.
Running above migration will generate the following migration file:
The references
method supports the following options, index
and foreign_key
. So if you want to set index
to true
, you can declare it as:
t.references :authors, foreign_key: true, index: true
comment
We can also specify comments to the table and its attributes explicitly in the migration file which would help people understand the data model.
class CreateAuthors < ActiveRecord::Migration[5.2]
def change
create_table :authors, comment: 'Authors who have published best-selling books' do |t|
t.string :name, comment: 'Name of Author'
t.integer :age
t.timestamps
end
end
end
:comment
, is declared as key:value
pair, where value contains the description of it. These are stored in the database itself. We can view these comments when running the migration, or in db/schema.rb
file, or with Database Administration Tools such as MySQL Workbench or PgAdmin III. :comment
is currently only supported by MySQL and PostgreSQL.
An alternate way to create a table
rails g migration CreateBook title:string authors:references
Our migration name here is CreateBook
. Whatever migration name we declare, that name will be set as our migration class name.
We use Create
keyword followed by the singular table name. This will tell Active Record to invoke the create_table
method and create the following attributes with the column-type specified.
The difference between this migration and the earlier model
migration is that this migration only creates a migration file and not the corresponding model file.
Another difference is that this migration doesn’t implicitly create the timestamps
method in the migration file. So running this migration will not create created_at
and updated_at
columns. To avoid this, we would need to explicitly mention the t.timestamps
method under the scope of the create_table
method.
The timestamps
method is also another special helper method.
However, the primary key will be implicitly created with the default name as id
.
Setting unique to an attribute
rails g model Book title:string:uniq
generates…
Giving unique
to the title
attribute invokes add_index
method, so not only our attributes’ values will be unique but its index
is also set to true
.
What is Index?
If you have a large database with millions of records and high traffic, the responses become slow, so extracting data becomes more time-consuming as records increase. If we’re extracting the same attribute, again and again, for example, email or username or a foreign key, using index
to it would make operations faster & efficient as queries would be easily searchable because index
creates a copy of that attribute and sorts them in alphabetical order.
For more info on this, refer to this post.
Unique
It does not allow duplicate values in the same column/attribute in a table.
Supported column-types
Active Record supports the following database column types:
binary
boolean
date
datetime
decimal
float
integer
primary_key
string
text
time
timestamp
You may use a type that is not in this list as long as it is supported by your database, for example, using polygon
in MySQL. But this won’t be database agnostic and should usually be avoided.
This article gives a detailed explanation of each column type and what column types are available to use for different databases.
Delete Migration Files
Now let’s see how to destroy migration files, assuming we have a model class named Book
:
rails destroy model Book
Output:
Running via Spring preloader in process 33047
invoke active_record
remove db/migrate/20210721053723_create_books.rb
remove app/models/book.rb
invoke test_unit
remove test/models/book_test.rb
remove test/fixtures/books.yml
All 4 files that were created when running generate
, will be deleted with destroy
!
Warning:
If you have already run the migrations on it, you need to manually rollback those migrations that created or updated this table in anyway, so that it updates the schema accordingly and we don’t run into errors when runningdb:migrate
task, asdestroy
command just deletes the files that generated whenmigration
was ran and not the table in database, there's no coming back from it!
After creating migration files, in Part 2 we will look into how to generate a corresponding table of it in the database.
Part 2: Executing Migration Files