rails 数据库迁移

  • 任何对数据库的操作(改变表的结构),必须使用migration
    • 创建表
    • 修改表
    • 删除表
    • 新增列
    • 修改列
    • 删除列
  • migration 一旦创建好,并且上传到了远程服务器,就绝对不能做改动。

创建

例如:我想新建一个表users, 它有个属性: name, age

就通过rails generate migration 命令创建:

$ bundle exec rails g migration create_users
      invoke  active_record
      create    db/migrate/20160308125025_create_users.rb

可以看到,上面的命令, 建立了文件: db/migrate/20160308125025_create_users.rb

打开这个文件, 并且编辑它的内容, 如下:

class CreateUsers < ActiveRecord::Migration

  def up

    # 建立 users 表
    create_table :users do |t|

      # 建立列: name, 类型是string
      t.string :name

      # 建立列: age, 类型是 integer
      t.integer :age

      # 建立created_at 与 updated_at , 类型都是 datetime
      t.timestamps
    end
  end

  def down

    # 删掉 users 表
    drop_table :users
  end
end

up/down 与 change的区别.

(如果你用rails 4.x 来创建的话,得到的migration ,一般没有up, down 方法。因为,rails 非常智能,能自动的,把 up, down方法合并成: change

例如,如果up方法中,是create_table, 那么,rails就会自动判断出,在down 方法中,就用drop_table

但是,还是有些时刻,rails无法自动判断up/down, 例如: 改变某个列的类型。这个时候,还的 使用经典的 up/down方法。

对于新手, 建议使用 up/down 方法.免得被 change 弄糊涂.)

运行 rake db:migrate

接下来, 运行 rake db:migrate:

$ bundle exec rake db:migrate
== 20160308125025 CreateUsers: migrating ======================================
-- create_table(:users)
   -> 0.0078s
== 20160308125025 CreateUsers: migrated (0.0079s) =============================

我们打开这个数据库,发现数据库中,新增了一个表 users.

sqlite> .tables
schema_migrations  users

回滚

回滚,就是通过一条命令,rake db:rollback 来执行对应的migration中的down方法。

$ bundle exec rake db:rollback
== 20160308125025 CreateUsers: reverting ======================================
-- drop_table(:users)
   -> 0.0012s
== 20160308125025 CreateUsers: reverted (0.0068s) =============================

可以看到,table中就少了:users

sqlite> .tables
schema_migrations

下面,是另一个完整的例子,可以看到 down 中的方法,与 up 是相反的:


class RenameAgeToNianLingFromUsers < ActiveRecord::Migration

  def up
    rename_column :users, :age , :nian_ling
  end

  def down
    rename_column :users, :nian_ling, :age
  end
end

schema_migrations: 记录迁移过程的表

可能有的同学会比较奇怪: schema_migrations, 这个是干嘛的呢?

这个表专门记录当前数据库的 "迁移ID" 是多少。 Rails就是通过比较它和 db/migrate 中文件的差异来判断, 当前的rails,的数据库,是否是最新的。

例如, 运行 CreateUsers 这个migration之前:

sqlite> select * from schema_migrations;
20151023070737

运行完之后:

sqlite> select * from schema_migrations;
20151023070737
20160308125025

多出来的一行: 20160308125025 , 刚好就是我们新建的migration : 20160308125025_create_users名字的一部分。

(一旦某个rails的正式项目,开始之后,这个表的内容会很多)

如何修改一个列?

错误的做法:

  1. 运行回滚操作: rake db:rollback
  2. 修改migration文件的内容。 在其中增加 change_column方法. (具体代码略)
  3. $ rake db:migrate

绝对错误!记住: 一旦创建好migration文件(特别是已经提交到了远程的话),就绝对不要去修改它!

因为一rollback的话,迁移的时间线就立马乱了。

正确的做法是:

  1. 新建个migration. (在这个migration中,使用 change_column 方法,来修改)
  2. 运行它

例子

例如,我想把 age 列,改名字,改成: nian_ling, 我应该:

1.运行命令:

$ bundle exec rails g migration rename_age_to_nian_ling_from_users_table

这里的migration的命名(在上面,就是 rename_age_to_nian_ling_from_users_table ),不是特别严格的。不会引起错误。但是原则上,migration 要看到名字, 就能知道它是做什么的。 例如:

  • create_users: 创建users 表
  • remove_name_from_users: 从users表中删掉 name列.

然后得到结果.

$ bundle exec rails g migration rename_age_to_nian_ling_from_users
      invoke  active_record
      create    db/migrate/20160308130535_rename_age_to_nian_ling_from_users.rb

2.编辑上面命令,产生的文件。

# db/migrate/20160308130535_rename_age_to_nian_ling_from_users.rb
class RenameAgeToNianLingFromUsers < ActiveRecord::Migration
  def change

    # 手动增加下面这行代码:
    rename_column :users, :age, :nian_ling
  end
end

3.运行 rake db:migrate

$ bundle exec rake db:migrate
== 20160308130535 RenameAgeToNianLingFromUsers: migrating =====================
-- rename_column(:users, :age, :nian_ling)
 -> 0.0111s
== 20160308130535 RenameAgeToNianLingFromUsers: migrated (0.0112s) ============

就能够看到,schema_migrations 表中,增加了一条记录, 就是我们刚才运行的migration的时间戳.

sqlite> select * from schema_migrations;
20151023070737
20160308125025
20160308130535

并且, users表中,age列变成了 nian_ling列。

sqlite> .schema
...
CREATE TABLE "users" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
    "name" varchar(255),
    "nian_ling" integer,
    "created_at" datetime,
    "updated_at" datetime
);
sqlite>

常见的migration方法

注: 以下方法都写在up, down 或者change方法中.

  • create_table

例如, 创建表 'students' :

create_table :students do |t|
  t.string :chinese_name
  t.integer :age
  t.timestamps
end

上面的 t.timestamps, 会创建两个列: created_at, updated_at.

  • created_at: 表示 该条记录,在什么时间被创建的。
  • updated_at: 表示 该条记录,在什么时间被修改的。

等同于:

  t.datetime :created_at
  t.datetime :updated_at

rails中几乎每个表,都默认有这两个列。

  • drop_table

例如,删掉表'students' :

drop_table :students
  • add_column

例如, 向'students' 表中,增加一个列'name', 它的类型是字符串:

add_column :students, :name, :string
  • remove_column

例如, 从'students' 表中,删除列'name':

remove_column :students, :name
  • rename_column

例如, 把'students' 表的'chinese_name'列, 重命名为 'zhong_wen_ming_zi':

rename_column :students, :chinese_name, :zhong_wen_ming_zi
  • add_index

例如, 把'students'表的name列建立索引:

add_index :students, :name
  • remove_index

例如, 把'students'表的已经存在的name索引删掉:

remove_index :students, :name

几个注意:

  • 所有的model , 都是单数。
  • 所有的controller, 都是复数(原则上)
  • 所有的table, 都是复数。(例如: egg => eggs, person => people, wife -> wives)

如果弄错了,rails的代码在默认配置下就会出错。

不学的内容

不要这样写, 容易乱:

  def change
    create_table :appointments do |t|
      t.belongs_to :physician
      t.belongs_to :patient
      t.datetime :appointment_date
      t.timestamps
    end
  end

可以这样写(就把外键当成最普通的列就行了):

class CreateAppointments < ActiveRecord::Migration
  def change
    create_table :appointments do |t|
      t.integer :physician_id
      t.integer :patient_id
      t.datetime :appointment_date
      t.timestamps
    end
  end
end
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值