Skip to content

Instantly share code, notes, and snippets.

@bryanmytko
Last active December 14, 2016 16:53
Show Gist options
  • Save bryanmytko/b0407ead43bac5e93c4f8153ba3b9aae to your computer and use it in GitHub Desktop.
Save bryanmytko/b0407ead43bac5e93c4f8153ba3b9aae to your computer and use it in GitHub Desktop.
Migration Files!

Editing Migration Files:

A Real Life Scenario

Jared starts a new project for his team. He creates a new User model using the generator:

rails g model User email:string name:string password_digest:string

This command creates two important files (among others), which are:

app/models/user.rb

db/migrate/20160101297348_create_users.rb

The model file is what Rails uses as the bridge between our code and the database. If you look inside the app/models/user.rb file you will see a class defined like:

  class User < ApplicationRecord
  end

Our User class inherits from ApplicationRecord, which is a class that gives us all the methods we learned like "first", "find", "where". This is less important and we could have created this file manually.

The migration file is what is important here. Migration files are what get executed when we call rails db:migrate. It runs only migration files that have not been run already, building out the database in chronological order.

Jared runs rails db:migrate and it creates a users table with three columns, email, name and password_digest.

Then Jared pushes his code up to Github and tells his team to pull.

Bryan and John pull the code down and run the migrations and start working on their features. At this time Jared realizes that name needs to actually be 'first name' and 'last name'. He goes in and EDITS THE MIGRATION FILE from:

  create_table :users do |t|
    t.string :email
    t.string :name
    t.string :password_digest

    t.timestamps
  end

to:

  create_table :users do |t|
    t.string :email
    t.string :first_name
    t.string :last_name
    t.string :password_digest

    t.timestamps
  end

He also updates a file in his helper to use the first and last name attributes:

  user = User.find(params[:id])
  puts "Greetings, #{user.name}"

to:

  user = User.find(params[:id])
  puts "Greetings, #{user.first_name}"

Note though that the migration file name remains the same. Jared rolls back his own migrations and reruns them, getting his new database table set up with the new columns. He then pushes the code to GitHub.

Meanwhile John has already added a Posts table and a Comments table to his branch. Bryan has merged some of this into his own branch as well. They've both run migrations several times. What will happen when they attempt to use Jared's code?

A Better Solution

Instead of editing a migration file, Jared should have created a new migration file that alters the existing table. Since the model already exists, we can just use the generator to create a migration file. The naming for a migration is arbitrary but should be descriptive. It would look something like this:

rails g migration AddFirstNameToUsers first_name:string

which creates a new migration file:

class AddFirstNameToUsers < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :first_name, :string
  end
end

And then another to rename the coumn name to last_name:

rails g migration ChangeNameToLastname

Which generates:

class ChangeNameToLastname < ActiveRecord::Migration[5.0]
  def change
  end
end

Note this is an empty migration file. Changing is too advanced to specify using the generator. We have to write it manually. See Active Record Migrations Documentation for more information.

We add this line:

class ChangeNameToLastname < ActiveRecord::Migration[5.0]
  def change
    rename_column :users, :name, :last_name
  end
end

Remember this is just a method call like rename_coumn(:table, :old_column_name, :new_column_name)

The key point here is that now when a user runs migrations, they will playback files in chronological order. It will build the table with the name column and then update it to use first and last name. This ensures that everyone has the exact same database!

@johnrbell
Copy link

This also ensures the ghost of Bryan Mytko doesn't haunt your laptop because you edited migrations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment