CS6320:  SW Engineering of Web Based Systems

 

Migration --- creating database tables

READ ruby guide on migrations here

 

migrations = way in RoR to alter database schema over time

Step 1: Create a Model class using generate tool in Rails (e.g. User Model class)

i.e. in RubyMine: Tools-> Run Rails Generator -> model

>>> give it the name User (in this example)

it will generate a file under app/models/model_name.rb AND also a db/migrate/****_model_name.rb file

Here is example when name of model is User

Step 2: edit the generated database migration file autogenerated for you in step 1 to add code to create table

SUPPOSE you have created a model called User it will create the following file for you.   Edit it as shown in red to add code to create the corresponding database table.

db/migrate/20090215220309_create_students.rb:

class CreateUsers < ActiveRecord::Migration



   def change
     create_table :students do |t|
            t.column :first_name,        :string
            t.column :last_name,       :string
     end
  end

end

 

 

HERE IS A DIFFERENT example for a Model Student

db/migrate/20090215220309_create_students.rb:

class CreateStudents < ActiveRecord::Migration



   def change
     create_table :students do |t|
            t.column :name,        :string
            t.column :birth,       :date
            t.column :gpa,         :float
            t.column :grad,        :integer
     end
  end

end

 

OPTIONAL: Step 3: create script file to load data already know

 

OPTIONAL!!!!! Here there is a file load_data.rb that contains some initial data you want to load

COMMAND LINE: rails generate migration load_data    

RubyMine IDE: Tools-> Run Rails Generator -> migration (then give the name load_data)

Example of a load_data.rb file

class LoadData < ActiveRecord::Migration
def up
# Create initial users.
down
jb = User.new(:first_name => "Justin", :last_name => "Bieber")
jb.save(:validate => false)
ph = User.new(:first_name => "Paris", :last_name => "Hilton")
ph.save(:validate => false)
mc = User.new(:first_name => "Miley", :last_name => "Cyrus")
mc.save(:validate => false)
bo = User.new(:first_name => "Barack", :last_name => "Obama")
bo.save(:validate => false)
sc = User.new(:first_name => "Santa", :last_name => "Claus")
sc.save(:validate => false)
jo = User.new(:first_name => "John", :last_name => "Ousterhout")
jo.save(:validate => false) end

def down
User.delete_all
end
end

 


 

 

step 4: Run migrations (latest)

 

COMMAND LINE: rake db:migrate
RubyMine IDE: Tools->Run Rake Task -> db:migrate

Following our example of ---this generates the following database table named:

users

id first_name last_name
primary key string string

By default, create_table will create a primary key called id.

You can change the name of the primary key with the :primary_key option (don't forget to update the corresponding model) 

If we had done the optional load_data file seen above this would be the contents of the users database

1 Justin Bieber
2 Paris Hilton
3 Miley Cyrus
4 Barack Obama
5 Santa Claus
6 John Ousterhout

 

 

SPECIAL WORD About the schema that is ALSO GENERATED when you perform migrations

From RoR guide:

What are Schema Files for? (YOU DONT EDIT THEM!!!!!)

Migrations, mighty as they may be, are not the authoritative source for your database schema. That role falls to either db/schema.rb or an SQL file which Active Record generates by examining the database. They are not designed to be edited, they just represent the current state of the database.

There is no need (and it is error prone) to deploy a new instance of an app by replaying the entire migration history. It is much simpler and faster to just load into the database a description of the current schema.

For example, this is how the test database is created: the current development database is dumped (either to db/schema.rb or db/structure.sql) and then loaded into the test database.

Schema files are also useful if you want a quick look at what attributes an Active Record object has. This information is not in the model's code and is frequently spread across several migrations, but the information is nicely summed up in the schema file. The annotate_models gem automatically adds and updates comments at the top of each model summarizing the schema if you desire that functionality.

Because schema dumps are the authoritative source for your database schema, it is strongly recommended that you check them into source control.

db/schema.rb contains the current version number of the database. This ensures conflicts are going to happen in the case of a merge where both branches touched the schema. When that happens, solve conflicts manually, keeping the highest version number of the two.

 

Example schema.rb file created from above

ActiveRecord::Schema.define(version: 20150105235326) do

create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"

end

end

 

 

 

 

 

SPECIAL WORD About Changing Migration file and rerunning---create a new one instead

"You should always create a new migration file when adding/changing something in the database. This is the purpose of migrations."

From RoR guide:

Occasionally you will make a mistake when writing a migration. If you have already run the migration then you cannot just edit the migration and run the migration again: Rails thinks it has already run the migration and so will do nothing when you run rake db:migrate. You must rollback the migration (for example with rake db:rollback), edit your migration and then run rake db:migrate to run the corrected version.

In general, editing existing migrations is not a good idea. You will be creating extra work for yourself and your co-workers and cause major headaches if the existing version of the migration has already been run on production machines. Instead, you should write a new migration that performs the changes you require. Editing a freshly generated migration that has not yet been committed to source control (or, more generally, which has not been propagated beyond your development machine) is relatively harmless.

The revert method can be helpful when writing a new migration to undo previous migrations in whole or in part (see Reverting Previous Migrations above).

NOT a suggestion but on the command line there is a

db:migrate:redo

and 
rake db:schema:dump

 

Quickly generate new migrations file to add say a new column in a table

rails generate migration add_columnname_to_tablename

example

rails generate migration add_gpa_to_students

 

 

 

ALTERNATIVE STEP 2 ---also add the timestamps macro

 

edit the generated database migration file autogenerated for you in step 1 to add code to create table but ADD the timestamp

 

The timestamps macro adds two columns, created_at and updated_at.

  • Both will be of the data type datetime.
  • These special columns are automatically managed by Active Record if they exist.   Ofcourse editing by hand requires input

 

SUPPOSE you have created a model called Student it will create the following file for you.   Edit it as shown in red to add code to create the corresponding database table.

db/migrate/20090215220309_create_students.rb:

class CreateStudents < ActiveRecord::Migration

    def change

     create_table :students do |t|

            t.column :name,        :string
            t.column :birth,       :date
            t.column :gpa,         :float
            t.column :grad,        :integer
            t.timestamps     null: false
       end
   end

end

 

This generates the following database table named:

students

id name birth gpa grad created_at updated_at
primary key string date float integer

datetime

(e.g. 2015-01-06 00:52:29.375922)

datetime

 

 

 

 

 

© Lynne Grewe