Skip to content

Instantly share code, notes, and snippets.

@pyk
Last active August 2, 2021 09:20
Show Gist options
  • Star 77 You must be signed in to star a gist
  • Fork 24 You must be signed in to fork a gist
  • Save pyk/8569812 to your computer and use it in GitHub Desktop.
Save pyk/8569812 to your computer and use it in GitHub Desktop.
become active record migration expert (Rails 4.0.2)

become active record migration expert (Rails 4.0.2)

workflow:

create model

$ rails g model NameOfModel
    invoke  active_record
    create    db/migrate/YYYYMMDDHHMMSS_create_name_of_models.rb
    create    app/models/name_of_model.rb
    invoke    test_unit
    create      test/models/name_of_model_test.rb
    create      test/fixtures/name_of_models.yml

create name_of_models table and define some columns

  1. open db/migrate/YYYYMMDDHHMMSS_create_name_of_models.rb

  2. define field in format t.field_type :field_name

class CreateNameOfModels < ActiveRecord::Migration
    def change
        create_table :name_of_models do |t|
            t.string :name
            t.integer :age
            t.timestamps
        end
    end
end
  1. run rake db:migrate
$ rake db:migrate
==  CreateNameOfModels: migrating =============================================
-- create_table(:name_of_models)
   -> 0.0085s
==  CreateNameOfModels: migrated (0.0087s) ====================================

this will create name_of_models table with name and age columns.

updating name_of_models table

add another column

  1. run rails generator with Add[column]To[model] format followed by column
$ rails g migration AddBioToNameOfModels bio:text
    invoke  active_record
    create    db/migrate/YYYYMMDDHHMMSS_add_bio_to_name_of_models.rb
  1. open db/migrate/YYYYMMDDHHMMSS_add_bio_to_name_of_columns.rb
class AddBioToNameOfModels < ActiveRecord::Migration
  def change
    add_column :name_of_models, :bio, :text
  end
end
  1. run rake db:migrate
› rake db:migrate
==  AddBioToNameOfModels: migrating ===========================================
-- add_column(:name_of_models, :bio, :text)
   -> 0.0067s
==  AddBioToNameOfModels: migrated (0.0069s) ==================================

add multiple columns at once

  1. run rails generator with AddDetailsTo[model] format followed by list of columns
$ rails g migration AddDetailsToNameOfModels first_name last_name phone_number anothertables:belongs_to
    invoke  active_record
    create    db/migrate/YYYYMMDDHHMMSS_add_details_to_name_of_models.rb
  1. open up db/migrate/YYYYMMDDHHMMSS_add_details_to_name_of_models.rb
class AddDetailsToNameOfModels < ActiveRecord::Migration
    def change
        add_column :name_of_models, :first_name, :string
        add_column :name_of_models, :last_name, :string
        add_column :name_of_models, :phone_number, :string
        add_reference :name_of_models, :anothertables, index: true
    end
end

make sure you have exactly column name and type before migrating

  1. run rake db:migrate
$ rake db:migrate
==  AddDetailsToNameOfModels: migrating =======================================
-- add_column(:name_of_models, :first_name, :string)
   -> 0.0068s
-- add_column(:name_of_models, :last_name, :string)
   -> 0.0009s
-- add_column(:name_of_models, :phone_number, :string)
   -> 0.0008s
-- add_reference(:name_of_models, :anothertables, {:index=>true})
   -> 0.0016s
==  AddDetailsToNameOfModels: migrated (0.0108s) ==============================

remove column

  1. run rails generator with Remove[column]From[model] format followed by column you want to remove
$ rails g migration RemovePhoneNumberFromNameOfModels phone_number:string
      invoke  active_record
      create    db/migrate/YYYYMMDDHHMMSS_remove_phone_number_from_name_of_models.rb
  1. open db/migrate/YYYYMMDDHHMMSS_remove_phone_number_from_name_of_models to make sure.
class RemovePhoneNumberFromNameOfModels < ActiveRecord::Migration
    def change
        remove_column :name_of_models, :phone_number, :string
    end
end

remove multiple columns at once

  1. run rails generator with RemoveDetailsFrom[model] format followed by column you want to remove
› rails g migration RemoveDetailsFromNameOfModels first_name last_name anothertables:belongs_to
      invoke  active_record
      create    db/migrate/YYYYMMDDHHMMSS_remove_details_from_name_of_models.rb
  1. open db/migrate/YYYYMMDDHHMMSS_remove_details_from_name_of_models.rb
class RemoveDetailsFromNameOfModels < ActiveRecord::Migration
    def change
        remove_column :name_of_models, :first_name, :string
        remove_column :name_of_models, :last_name, :string
        remove_reference :name_of_models, :anothertables, index: true
    end
end
  1. if you are sure with what you do, then run rake db:migrate. it will remove all column or reference that you define on db/migrate/YYYYMMDDHHMMSS_remove_details_from_name_of_models.rb

tips

  • when you migrate the wrong table you can rollback using rake db:rollback
  • update your table with create new migration (add/remove).

I think, updating your table by editing your previous migration is not best practice. my experience updating table by editing my previous migration and then execute rake db:migrate is doesn't work.

more resource

Active Record Migrations

@AnjanJ
Copy link

AnjanJ commented Sep 30, 2015

Great explanation. made everything so simple.
Thanks for the post

@harsh183
Copy link

harsh183 commented Dec 1, 2015

Thanks for this post, it makes things very clear.

@itayariely
Copy link

is it possible to create new generator that drop_table / change column name or type / remove columns / change table name.

For example I would like to be able to write:
Rails g migration DropTable User

and without any file migration edition run:
rake db:migrate

@AdKnob
Copy link

AdKnob commented Apr 8, 2017

Thank you. Finally clicked for me.

@Iqlaas
Copy link

Iqlaas commented Jun 19, 2017

If you could add that you could verify the migration works in the console it would be perfect !

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