The Ruby On Rials Gudie -- Active Record Migrations
中文就是数据迁移,它是用来更改数据库的,但是它有一个挺好的设计,就是他会记录你更改的历史,你每次修改都会单独生成一个文件,然后在前一个的基础上修改。这样假如你发现了设计中的失误,那么你可以回滚到你觉得正确的版本上去。并且它的修改不是SQL级别,它是Ruby SDL级的。你的db/schema.rb反映了你的表
下面给一个小例子
class
CreateProducts < ActiveRecord::Migration
def
change
create_table
:products
do
|t|
t.string
:name
t.text
:description
t.timestamps
end
end
end
这个就是一个migration(以后我们就用这个英文词,因为中文翻译的感觉很怪,并且你以后命令也少不了用这个词什么的,早点熟悉),它创建了一个products的表。这样就ok了
具体描述这个表原英文是这样的,很简单,就不翻译了。注意它自动生成了id这个primary key,还有因为timestaps新加了两列
This migration adds a table called products
with a string column called name
and a text column called description
. A primary key column called id
will also be added implicitly, as it's the default primary key for all Active Record models. The timestamps
macro adds two columns, created_at
and updated_at
. These special columns are automatically managed by Active Record if they exist.
创建一个Migration
我们的migration生成的文件名字格式是这样的 YYYYMMDDHHMMSS_create_products.rb 解释下, 第一个下划线前的是UTC时间(不理解UTC没关系的,知道它是个时间戳就ok了,能够反映我们这个文件的创建的日期),第一个和第二个下划线间的是操作名(我们这里是创建,以后还可以有很多操作),第二个下划线后的是表的名字(注意,这里是复数形式,这个就体现出来了rails的命名规则的变化了,还是很有意思的,他是复数,那么就说明他是表)。
假如我们生成一个自己的Migration,其实很简单的,参考下面的命令
rails generate migration AddPartNumberToProducts
这个就ok了,他会生成一个类似的名字YYYYMMDDHHMMSS_add_part_number_to_products.rb的文件,这里进行了个命名规则的变化(其实也很简单,在rails中,model是采用驼峰式命名规则,而其余的是采用下划线的明明规则,更准确的说是只要要求大写的,是采用驼峰式命名规则的,其余的都是用下划线的),这个文件中像下面的一样
class
AddPartNumberToProducts < ActiveRecord::Migration
def
change
end
end
这是一个空的migration,我们的操作是change里面的操作,只要从里面写出来就行了。
具体几类操作:
一. create一个表
命令就是这样的
rails generate migration CreateProducts
这是最主要的命令,他会生成一个这样的文件
classCreateProducts < ActiveRecord::Migrationdefchange
end
end
假如你想创建一个带有name和part_number列的表,你可以修改这个文件为下面的,就ok了,他们的属性是文本
class
CreateProducts < ActiveRecord::Migration
def
change
create_table
:products
do
|t|
t.string
:name
t.string
:part_number
end
end
end
很简单吧,其实还可以更简单,这样一个命令,足矣
rails generate migration CreateProducts name:string part_number:string
功效是一样的
二. 增加一个column,这个也很简单
rails generate migration AddDetailsToProducts part_number:string price:decimal
这样子他就生成了
class
AddDetailsToProducts < ActiveRecord::Migration
def
change
add_column
:products
,
:part_number
,
:string
add_column
:products
,
:price
,
:decimal
end
end
这样一个文件,就增加了两个列,当然,你也可以
rails generate migration AddDetailsToProducts
然后在修改的了
假如你想在新的列上家一个索引,那么也可以这样执行的
rails generate migration AddPartNumberToProducts part_number:string:index
这样他就增加了一个part_number的列了,并且加上了索引
生成了下面的一个文件
class
AddPartNumberToProducts < ActiveRecord::Migration
def
change
add_column
:products
,
:part_number
,
:string
add_index
:products
,
:part_number
end
end
三. 删除一列
rails generate migration RemovePartNumberFromProducts part_number:string
这样就删除了part_number这个列
生成了这样文件
class
RemovePartNumberFromProducts < ActiveRecord::Migration
def
change
remove_column
:products
,
:part_number
,
:string
end
end
总结下,对于命令解释下吧(小技巧,g可以代替generate)
创建表:rails g migration CreateXXX 后面可以跟着列的名字和对应的格式
增加列:rails g migration AddXXX后面可以跟着列的名字和对应的格式加上:index的话就可以加一个索引
删除列:rails g migration RemoveXXX 后面可以跟着列的名字和对应的格式
其实区别就是第一个单词,记住一定要使用驼峰命名规则,rails讲究是约定优于规则,遵守rails的命名规则书写规则什么的,rails才会更好的和你玩
手写migration
虽然rails的migration很神奇,有人甚至说这是rails的魔法,但是我们还是要手写migration来真正明白它是做了怎么回事,我们所书写的全部是要在那个migration 的file中的change中的。
1. 先说创建表,用的函数是create_table
用法
create_table
:products
do
|t|
t.string
:name
end
这样就创建了一个有一个类型为文本名字为name的名叫products的表,很简单。对了,他会默认的创建一个叫id的列,类型是数字类型,作为主键的。
2. 创建一个join表,就是建立两个表的级联
create_join_table
:products
,
:categories
这样就创建了一个表叫做categories_products 假如你想自己定义名字的话就用下面的
create_join_table
:products
,
:categories
, table_name:
:categorization
这样就ok了
这个表中有两列,并且非空。叫做product_id和category_id(注意是单数形式)。当然那你可以自己定义一些列的属性
这样用
create_join_table
:products
,
:categories
, column_options: {null:
true
}
在column_options中设定
3.修改一个表changing tables
用的方法叫change_table,他遍历整个数据,然后进行修改
change_table
:products
do
|t|
t.remove
:description
,
:name #移除description 和 name 列
t.string
:part_number # 增加一个string类型叫做part_number的列
t.index
:part_number #为part_number的列加上索引
t.rename
:upccode
,
:upc_code #修改upccode列的名字为upc_code
end
t提供了很多方法,比如remove,index,rename。分别是移除,加上索引,重民名,而那个string是声明了一个part_number的列,具体的我从上面注释了
4. 直接执行sql
Products.connection.execute(
'UPDATE `products` SET `price`=`free` WHERE 1'
)
这里你创建的model叫product,所以你的数据库中的表是products,而这个貌似是也有点model的意思,所以大写了。所以这样就可以执行啦
总之 修改表可以使用的方法如下,只有这些方法是支持回滚的
add_column
add_index
add_reference
add_timestamps
create_table
create_join_table
drop_table
(must supply a block)drop_join_table
(must supply a block)remove_timestamps
rename_column
rename_index
remove_reference
rename_table
当我们使用migration做的事情很复杂时,我们想回滚,有些migration不知道该如何做的,我们可以用更加复杂的reversible来说明如何做一个例子通过这个例子,我们要明白的只有两个事,up和down,up就是你执行它的时候如何办,down就是回滚时如何办
class
ExampleMigration < ActiveRecord::Migration
def
change
create_table
:products
do
|t|
t.references
:category
end
reversible
do
|dir|
dir.up
do
#add a foreign key
execute <<-
SQL
ALTER
TABLE
products
ADD
CONSTRAINT
fk_products_categories
FOREIGN
KEY
(category_id)
REFERENCES
categories(id)
SQL
end
dir.down
do
execute <<-
SQL
ALTER
TABLE
products
DROP
FOREIGN
KEY
fk_products_categories
SQL
end
end
add_column
:users
,
:home_page_url
,
:string
rename_column
:users
,
:email
,
:email_address
end
这个是rails 4.0 中的新写法,同样支持以前的rails的书写方法,就是吧up和down直接卸载change下面例如下个例子class
ExampleMigration < ActiveRecord::Migration
def
up
create_table
:products
do
|t|
t.references
:category
end
# add a foreign key
execute <<-
SQL
ALTER
TABLE
products
ADD
CONSTRAINT
fk_products_categories
FOREIGN
KEY
(category_id)
REFERENCES
categories(id)
SQL
add_column
:users
,
:home_page_url
,
:string
rename_column
:users
,
:email
,
:email_address
end
def
down
rename_column
:users
,
:email_address
,
:email
remove_column
:users
,
:home_page_url
execute <<-
SQL
ALTER
TABLE
products
DROP
FOREIGN
KEY
fk_products_categories
SQL
drop_table
:products
end
end
其实这个回滚还是有其他的写法的,但是我觉得这种就足够用了,还有一种可以用其他版本的reversible函数的方法,不过感觉很鸡肋,第一很难说能用到,第二这样开发不同版本间的依赖性太高了,不好。有兴趣可以查看下。
运行migration
用法很简单
rake db:migrate
这样将按顺序执行还没有被migrate的migration
rake db:migrate VERSION=20080906120000
这样他将执行特定时间戳的版本
回滚
rake db:rollback
回滚一步
rake db:rollback STEP=3
回滚三步
重置数据库
rake db:reset
在特定环境中执行
rake db:migrate RAILS_ENV=test
其他的还有一些比如执行特定migration的up或者down函数啊,修改输出信息啥的。用的机会不大,不再单独写出。