参考资料:http://guides.rubyonrails.org/migrations.html
一、Migrations:
1、名字:
文件名就是个普通的ruby文件名前面加上时间戳,类名的命名规则跟普通的ruby类没什么两样,只是要把前面的时间戳去掉,比如文件名为20080906120001_add_details_to_products.rb的migration类名应该是AddDetailsToProducts。
rails只把时间戳部分作为识别migration的id,所有执行过的migration的id都将被保存到数据库的schema_migrations表中。在rails2.1之前的版本中,migration的id是从1开始增长,但是,很容易想到,在多人合作开发项目的时候,这样会很有问题。
当然,
在新版本的rails中也可以通过在environment.rb设置config.active_record.timestamped_migrations的值为false来使用旧的方式生成migration的id。
(还是直接copy起来爽快……)
引用
The combination of timestamps and recording which migrations have been run allows Rails to handle common situations that occur with multiple developers.
For example Alice adds migrations 20080906120000 and 20080906123000 and Bob adds 20080906124500 and runs it. Alice finishes her changes and checks in her migrations and Bob pulls down the latest changes. Rails knows that it has not run Alice’s two migrations so rake db:migrate would run them (
even though Bob’s migration with a later timestamp has been run), and similarly migrating down would not run their down methods.
2、修改migrations
如果写错了一个migration并且运行过,别直接修改它然后再次rake db:migrate,因为rails并不知道你修改了migration,执行rake db:migrate时rails并不会做任何事。正确的做法是,先rake db:migrate:down或者rake db:rollback,然后再编辑这个migration,最后再次rake db:migrate。
一般来说最好不要去编辑一个已经存在了的migration,即便里面有错误。
引用
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.
最好的做法是写一个新的migration来执行修复上一个写错了的migration的操作。
引用
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. Just use some common sense.
3、创建migrations
generate model和generate scaffold命令都会创建一个migration,用于生成model对应的数据库结构。如果想要执行其它的修改数据库结构的操作——比如说给某个表添加一个字段,可以用generate migration来手动创建一个migration。这3种创建migration的命令的格式都一样:
ruby script/generate scaffold|model|migration migration_name column_name:column_type ...
如果migration_name的名字格式是像“add_xxx_to_xxx”或者“remove_xxx_from_xxx”这样的(经试验,也可以用驼峰命名法,像这样:AddXXXToXXX),并且后面跟着字段名和类型列表,那么rails将自动把add_column和remove_column指令加到生成的migration代码当中。例如:
ruby script/generate migration add_part_number_to_products part_number:string
将会生成:
class AddPartNumberToProducts < ActiveRecord::Migration
def self.up
add_column :products, :part_number, :string
end
def self.down
remove_column :products, :part_number
end
end
这样的ruby代码。
4、writing a migration
建表
create_table :products do |t|
t.string :name
end
以上代码将会创建一个名为products的表,其中包含一个名为name的字符类型字段。还有一种建表的方式是用bloc参数t的column方法,像这样:
create_table :products do |t|
t.column :name, :string
end
引用
the first form(原文是second,我把代码的顺序调换了一下), the so called “sexy” migration, drops the somewhat redundant column method. Instead, the string, integer, etc. methods create a column of that type. Subsequent parameters are the same.
create_table方法默认会创建一个名为id的整型自增长字段作为主键(
google了一下,要使用uuid作为主键可参考:
http://iceskysl.1sters.com/?p=349)。如果不想使用默认的id作为主键名称,可以使用:primary_key来指定某一个字段为主键。如果要创建一个不带主键的表(比如说一个多对多关联的“中间表”就不需要主键),可以传递一个hash :id=>false给create_table方法。
引用
The types supported by Active Record are :primary_key, :string, :text, :integer, :float, :decimal, :datetime, :timestamp, :time, :date, :binary, :boolean.
修改表结构
change_table :products do |t|
t.remove :description, :name
t.string :part_number
t.index :part_number
t.rename :upccode, :upc_code
end
以上代码修改了products表结构,删除了其中的description和name字段,添加了一个字符类型的part_number字段,并且给part_number字段添加索引,最后把upccode字段改名为upc_code。上面的代码完成的事和以下代码是一样的:
remove_column :products, :description
remove_column :products, :name
add_column :products, :part_number, :string
add_index :products, :part_number
rename_column :products, :upccode, :upc_code
引用
You don’t have to keep repeating the table name and it groups all the statements related to modifying one particular table. The individual transformation names are also shorter, for example remove_column becomes just remove and add_index becomes just index.
4、运行Migration
运行 db:migrate的时候,同时会调用 db:schema:dump这个任务,这个任务是用来更新db/schema.rb文件,使之与你的数据库结构匹配。
db:migrate:up和db:migrate:down都需要一个VERSION参数,用来指定目标版本,版本号就是migration的id,也就是那个时间戳。前者调用migration中的up方法,后者调用down方法。
db:migrate也可以设置VERSION参数,如果指定版本低于当前版本,所有在当前版本号跟指定版本号之间的migration(包括当前版本但不包括目标版本)的down方法将会被按版本号降序调用。如果指定版本号高于当前版本号,则所有在当前版本号跟指定版本号之间的migration(不包括当前版本但包括目标版本)的up方法将会被按版本号升序调用。
与db:migrate:up和db:migrate:down所不同的是,db:migrate经常是批量的执行N个migration的up或down方法,而db:migrate:up和db:migrate:down只能执行一个(指定的那个)migration的up或者down方法。
还有两种批量执行migrate任务的方法是db:rollback和db:migrate:redo,这两个任务都需要一个参数STEP,用于指定执行的步数。rollback懒得写了,看字面意思就很明白:rake db:rollback STEP=3。db:migrate:redo STEP=3将会从当前版本开始,往回执行最后3个版本的migration的down方法,也就是说前面这一步跟rollback STEP=3一样,然后再回来按升序执行migration的up方法。唉,表达能力好差,原文是这样的:
引用
The db:migrate:redo task is a shortcut for doing a rollback and then migrating back up again.
最后,
db:reset 任务将会卸载整个数据库,接着通过运行db/schema.rb重新创建整个数据库。关于这个schema.rb,看看它源代码内的注释(里边还提到一个db:schema:load):
引用
# This file is auto-generated from the current state of the database. Instead of editing this file,
# please use the migrations feature of Active Record to incrementally modify your database, and
# then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
# to create the application database on another system, you should be using db:schema:load, not running
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
引用
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 is all summed up in the schema file. The annotate_models plugin, which automatically adds (and updates) comments at the top of each model summarising the schema, may also be of interest.
There are two ways to dump the schema. This is set in config/environment.rb by the config.active_record.schema_format setting, which may be either :sql or :ruby.
If :ruby is selected then the schema is stored in db/schema.rb.
===2009 09 14===
刚看到个论坛里的帖子,写得比我早,做个链接过去:http://www.iteye.com/topic/423860