有时你在写迁移任务的时候可能会不小心写错,如果你已经执行了这个迁移任务,那么, 你就不能单纯地把它修改一下再重新执行一次, Rails 会认为这个迁移任务已经执行过了, 所以执行 rake db:migrate 时不会做任何操作。你应该先把写错的那个迁移任务回滚(可以执行 rake db:rollback),然后修改你的migration再执行 rake db:migrate 去 执行正确的版本。
新增一個 Migration 檔案
rails g migration migration_name
migration_name 常見的命名方式有Add欄位名To表格名
或是Remove欄位名From表格名
,不過這沒有一定,能描述目的即可。
rails generate model Product name:string description:text
rails generate migration AddPartNumberToProducts
rails generate migration AddPartNumberToProducts part_number:string
rails generate migration RemovePartNumberFromProducts part_number:string
對資料表做修改:
- create_table(name, options) 新增資料表
- drop_table(name) 移除資料表
- rename_table(old_name, new_name) 修改資料表名稱
- change_table 修改資料表欄位
個別修改資料表欄位:
- add_column(table, column, type, options) 新增一個欄位
- rename_column(table, old_column_name, new_column_name) 修改欄位名稱
- change_column(table, column, type, options) 修改欄位的型態(type)
- remove_column(table , column) 移除欄位
新增、移除索引:
- add_index(table, columns, options) 新增索引
- remove_index(table, index) 移除索引
記得將所有外部鍵 foreign key 加上索引
Rails中的型態 | 說明 | MySQL | Postgres | SQLite3 |
---|---|---|---|---|
:string | 有限長度字串 | varchar(255) | character varying(255) | varchar(255) |
:text | 不限長度文字 | text | text | text |
:integer | 整數 | int(4) | integer | integer |
:float | 浮點數 | float | float | float |
:decimal | 十進位數 | decimal | decimal | decimal |
:datetime | 日期時間 | datetime | timestamp | datetime |
:timestamp | 時間戳章 | datetime | timestamp | datetime |
:time | 時間 | time | time | datetime |
:date | 日期 | date | date | date |
:binary | 二進位 | blob | bytea | blob |
:boolean | 布尔值 | tinyint | boolean | boolean |
:references | 用來參照到其他Table的外部鍵 | int(4) | integer | integer |
下面的列表展示了sql和ruby间的数据类型对应关系:
SQLType Ruby Class
int, integer Fixnum
decimal, numeric Float
clob, blob, text String
interval, date Date
float, double Float
char, varchar, string String
datetime, time Time
Boolean -
有 一个潜在的可能是关于decimal的,在数据库里,使用decimal的列来存储number和fix number型,Active Record将decimal映射成Float类的对象,尽管这样可以应用于大多数应用,浮点数是不精确的,在对这一类型的属性进行一系列操作的时候,可 能会发生舍入的错误,你也许可以使用integer类型来作为替代方案,例如,存储货币型的时候可以将元,角,分,分别存入不同的字段。做为一种选择,你 可以使用聚合(aggregations),使用多个分开的字段来构建货币类型。
另外,欄位也還有一些參數可以設定:
:null
是否允許NULL,預設是允許:default
預設值:limit
用於string、text、integer、binary指定最大值
Migration 搭配的 Rake 任務
- rake db:create 依照目前的 RAILS_ENV 環境建立資料庫
- rake db:create:all 建立所有環境的資料庫
- rake db:drop 依照目前的 RAILS_ENV 環境刪除資料庫
- rake db:drop:all 刪除所有環境的資料庫
- rake db:migrate 執行Migration動作
- rake db:rollback STEP=n 回復上N個 Migration 動作
- rake db:migrate:up VERSION=20080906120000 執行特定版本的Migration
- rake db:migrate:down VERSION=20080906120000 回復特定版本的Migration
- rake db:version 目前資料庫的Migration版本
- rake db:seed 執行 db/seeds.rb 載入種子資料
如果需要指定Rails環境,例如production,可以輸入 RAILS_ENV=production rake db:migrate
bulk參數
:bulk => true
可以讓變更資料庫欄位的Migration更有效率的執行,如果沒有加這個參數,或是直接使用add_column
、rename_column
、remove_column
等方法,那麼Rails會拆開SQL來執行
要变更现有的数据表,可以用 create_table 的类似方法 change_table。它的用法跟create_table 差不多,但它的代码块有更多的方式。例如:
change_table :products do |t| t.remove :description , :name t.string :part_number t.index :part_number t.rename :upccode , :upc_code end |
移除了两个字段 description 和 name,创建了一个 part_number 的字符串类型字段并 为其添加了索引。最后重命名了 upccode 字段。
在一些情况下,Rails会知道如何去恢复所做的改变,使用change方法可以让我们不用同 时写up和down方法。目前来说change方法只支持以下migration的定义:
- add_column
- add_index
- add_timestamps
- create_table
- remove_timestamps
- rename_column
- rename_index
- rename_table
如果你需要使用其他方法,那么你就不能使用change方法而需要同时写up和down方法。
Migration里面的down方法能复原up方法所造成的变更。也就是说如果执行了up然后 再执行down,那么数据库的schema应该会没有改变。所以说,如果用up建立一个数据表, 就应该在down方法中删除它。明智的做法会使用跟up完全相反的顺便来做这些事情。
Rails提供一系列rake任务来执行migrations。第一个跟migration相关的rake任务是 rake db:migrate。它最基本有用法就是单纯地执行所有还没执行migrations的up或者 change方法。若所有migrations都执行过了,它就会直接结束。执行的顺序是按照migration 的日期。
值得注意的是执行db:migrate也会一起执行db:schema:dump,去更新db/schema.rb文件, 以便跟数据库的结构同步。
如 果你要migrate到某个特定版本,Active Record会执行所需的migrations(up,down,change) 直到到达指定的版本为上。所谓版本就是migration文件名前面的那串数字。例如要迁移到 版本20080906120000,只需执行:
$ rake db:migrate VERSION=20080906120000 |
如果指定的版本大于当前的版本(往上迁移),那么就会执行up方法到包含指定版本在内的 所有版本。如果是往下迁移的话则会执行所有down方法,但不包括指定版本本身。
rake db:rollback
如果你需要执行一个指定的migration的up或down方法,那么你可以用db:migrate:up和db:migrate:down这两个任务。你只需指定版本号,就可以触发它的up或down方法:
$ rake db:migrate:up VERSION=20080906120000 |
以上会执行20080906120000这个版本的migration的up方法。它会去确认这个migration之前有 没有跑过,所以,如果Active Record认为20080906120000已经跑过,那么执行 db:migrate:up VERSION=20080906120000将不会做任何操作。