在我们深入分析migration之前,我们先看几个例子。
class CreateProducts < ActiveRecord::Migration def up create_table :products do |t| t.string :name t.text :description t.timestamps end end def down drop_table :products end end
这个migration增加了一个products表,一个string类型的name,和一个text类型的description字段。
一个主键id 也会默认被加入,因为是默认的。所以不需要我们写出来。
Active Record里面流行的timestamp 类型的created_at和updated_at字段也会被加入。
撤销这个migration的动作非常简单,就是删除这个表。
migration不仅可以修改表的结构,你还可以用这个来修改数据库中不好的数据。
class AddReceiveNewsletterToUsers < ActiveRecord::Migration def up change_table :users do |t| t.boolean :receive_newsletter, :default => false end User.update_all ["receive_newsletter = ?", true] end def down remove_column :users, :receive_newsletter end end
这个migration在user表中增加了一个 receive_newsletter字段,我们设置对于新的user
默认是false。但已经存在的user被认为是已经做过了。所以我们使用User模型更新数据
既有的user这个字段为true.
rails 3.1对于migration提供了一个聪明的方法叫change。这个方法可以做任何表结构的migration。
这个方法知道怎么migration和撤销操作。那样的话你不需要写一个down方法了。
class CreateProducts < ActiveRecord::Migration def change create_table :products do |t| t.string :name t.text :description t.timestamps end end end
1.1 Migrations 是类
一个migration是ActiveRecord::Migration的子类,并且实现了
2个方法up 和down.
Active Record提供了下面的方法用来做表到migration.详细到将在会后面介绍。
add_column add_index change_column change_table create_table drop_table remove_column remove_index rename_column
如果你想对你的数据库做migration,例如创建一个外键。
然后执行任意的SQL来运行特定任务。
migration是一个普通ruby类,所以不仅限于这些功能。
例如,你可以在添加一个列之后,更新即存数据的
值。
如果一个支持事务语句数据库 (PostgreSQL or SQLite3),
migrations是被包含在事务中的。如果一个数据库不支持事务
语句(例如mysql),如果migration中的一部分运行失败,将不会
回滚,需要手动进行回滚。
1.2 在name中有什么
Migrations被存储在db/migrate文件夹下面。一个文件就是一个
Migration类。文件名到形式是:YYYYMMDDHHMMSS_create_products.rb
就是一个UTC时间加上下划线和migration的名字。
migration类的名字必须和日期之后到名字保持一致。
例如: 20080906120000_create_products.rb 类名应该是 CreateProducts
20080906120001_add_details_to_products.rb 类名应该是 AddDetailsToProducts
如果你改了文件名,别忘记类名也要改。要不然rails会出错。
rails内部使用时间来识别他们。rails 2.1里面id是用递增数字来识别的(从1开始)。
这样的设计,在多个用户使用的时候,很明显会产生冲突。但是你也可以通过设置
返回以前rails 2.1的id生成方法。
config.active_record.timestamped_migrations = false
后来用时间来代替id的生成方法,可以解决多个用户同时使用的时候到冲突。
例如:
alice加入了2个20080906120000 和 20080906123000的migration。
Bob加入了20080906124500,并且运行了。
Alice,发现bob更新了一个migration,他可以更新到最新。
当bob运行rake db:mgrate时候,rails会发现alice的migration没有做,
会自动做。
但有的改变无法自动识别,如果alice做了个表的删除。而bob还以为这个表还存在,
做表的migration将会出问题。
1.3 改变migration
有时候你可能在写migation的时候会犯错。如果你已经运行了到话,
只是编辑migration在重新运行一下是没用的。因为rails认为你已经
运行过了。所以你只能回滚,运行rake db:rollback。然后再运行你
修改好的migration。
如果一个很久之前的migration你想修改的话,建议是新建一个新的migration,
而不是修改旧的。这样将会产生额外的工作量。
1.4 支持的类型
Active Record支持下面的数据库类型
:binary :boolean :date :datetime :decimal :float :integer :primary_key :string :text :time :timestamp
这些将会匹配到各个数据库中的各种类型。
例如在mysql中String是代表 varchar(255).
你也可以,建立字段类型不使用activerecord提供的类型。
例如:
create_table :products do |t| t.column :name, 'polygon', :null => false end
不过这可能会妨碍其他数据库的移植性。