version: rails 4.1
3 编写数据迁移
一旦你已经创建了你的 migration,使用的是生成器中的一个,现在是时候让它工作了!
3.1 Creating a Table 创建表
create_table 方法是最基本方法之一,但大多数时候,使用一个 model 或者 scaffold 生成器来为你生成数据表。基本的用法如下:
create_table :productsdo|t| t.string :name end |
这创建了一个 products 数据表,有一个数据列名为 name (下面将会讨论这个,一个隐式的数据列)。
默认的情况下,create_table 将会创建一个主键叫做 id。你能够改变主键的名称,用 :primary_key 属性(不要忘了更新相对应的model)或者你根本不需要一个主键,你能够传入一个属性 id: false。如果你需要传入数据库的详细属性,你可以代入一个SQL块在 :options 属性。例如:
create_table :products, options: "ENGINE=BLACKHOLE"do|t| t.string :name, null: false end |
将会把 ENGINE=BLACKHOLE 添加到SQL语句,用来创建数据表(当使用MYSQL时候,默认的 ENGINE=InnoDB)。
3.2 Creating a Join Table 创建一个关联表
migration 方法 create_join_table 创建了一个 HABTM 关联表。通常的用法:
create_join_table :products, :categories |
创建了一个 categories_products 数据表,有两个列,名字是 category_id 和 product_id。这些列有属性 :null,默认设置false。这个能够被重写,通过声明 :column_options 属性。
create_join_table :products, :categories, column_options: {null: true} |
将会创建 product_id 和 category_id 其属性 :null 为 true。
你可以通过传入属性 :table_name,当你想要定制数据表名的时候。例如:
create_join_table :products, :categories, table_name: :categorization |
将会创建一个名为 categoriztion 的数据表。
create_join_table 也可以接受一段代码块,你可以用来增加索引(默认不会创建索引)或者额外的列:
create_join_table :products, :categoriesdo|t| t.index :product_id t.index :category_id end |
3.3 Changing Tables 更改表
create_table 的类似方法是 chang_table,用来更改已存在的数据表。它的用法和 create_table 非常的相似,对于代码块中产生对象有着更多的设置技巧。例如:
change_table :productsdo|t| t.remove :description, :name t.string :part_number t.index :part_number t.rename :upccode, :upc_code end |
移除了 description 和 name 的列,创建了一个 part_number string的列,以及增加了一个索引。最后它重命名了 upccode 列。
3.4 When Helpers aren't Enough 当缺少Helper的时候
如果由 Active Record 提供的 helpers 缺少时,你可以使用 execute 方法来生成任意的SQL:
Product.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') |
可以看到更多的细节和各个方法的例子,浏览API文档。尤其在这个文档中 ActiveRecord::ConnectionAdapters::SchemaStatements (提供了在change中可用的方法,up 和 down 方法),ActiveRecord::ConnectionAdapters::TableDefinition (通过 create_table 提供在对象生成中的可用方法),ActiveRecord::ConnectionAdapters::Table (通过 change_table 提供在对象生成中的可用方法)。
3.5 Using the change Method 使用改变方法
change 方法是编辑 migrations 的主要方式。它能搞定大部分的情况,Active Record 知道如何去 自动地回滚 migration。一般地,change 方法仅仅提供了这些 migration 定义:
- 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
change_table 同样也是可逆的,只要代码块没有调用 change,change_default 或者 remove。
如果你打算需要使用其他的方法,你应该使用 reversible 或者编写 up 和 down 方法来取代 change 方法。
3.6 Using reversible 使用回滚
复杂的 migrations 可能需要处理,Active Record 不知道如何去回滚。你能够使用 reversible 去指出 当运行一个 migration 时能做什么,当回滚时还能做其他的什么。例如:
classExampleMigration < ActiveRecord::Migration defchange create_table :productsdo|t| t.references :category end
reversible do|dir| dir.up do #add a foreign key execute <<-SQL ALTERTABLEproducts ADDCONSTRAINTfk_products_categories FOREIGNKEY(category_id) REFERENCEScategories(id) SQL end dir.down do execute <<-SQL ALTERTABLEproducts DROPFOREIGNKEYfk_products_categories SQL end end
add_column :users, :home_page_url, :string rename_column :users, :email, :email_address end end |
使用 reversible 将会确保,命令被执行到右边的顺序列表中。如果先前的migration例子被回滚了, down 代码块将会在 home_page_url 列被删除之后和products数据表被删除之前运行。
有的时候,你的 migration 将会做一些不可逆的操作;例如,可能要销毁一些数据。在这样的例子中,在你的down代码块中,你能够抛出 ActiveRecord::IrreversibleMigration。如果有些人尝试恢复你的 migration, 一个错误信息将被显示出来,提示这是不能够做的。
3.7 Using the up/down Methods 使用up/down方法
你也能够使用migration的旧类型,通过使用 up 和 down 方法替代 change 方法。up 方法应该描述了转换,你可以制定你的数据库模式,你的 migration 的 down 方法应该可以回滚up方法做的转换。也就是说,数据库模式应该是未改变的,如果你执行了up之后就执行down。例如,如果你在 up 方法中创建了一个数据表,你在 down 方法中应该删除它。在确切地回滚顺序中,他们被创建于 up 方法里,这是很明智地回滚转化过程。在可逆的部分例子是类似于:
classExampleMigration < ActiveRecord::Migration defup create_table :productsdo|t| t.references :category end
# add a foreign key execute <<-SQL ALTERTABLEproducts ADDCONSTRAINTfk_products_categories FOREIGNKEY(category_id) REFERENCEScategories(id) SQL
add_column :users, :home_page_url, :string rename_column :users, :email, :email_address end
defdown rename_column :users, :email_address, :email remove_column :users, :home_page_url
execute <<-SQL ALTERTABLEproducts DROPFOREIGNKEYfk_products_categories SQL
drop_table :products end end |
如果你的 migration 是不可逆的,你应该从 down 方法中抛出 ActiveRecord::IrreversibleMigration。如果有人想要尝试恢复你的 migration,一个错误的信息将被显示出来,提示他不能够被这样做。
3.8 Reverting Previous Migrations 恢复先前的migrations
你能够使用 Active Record 的能力来回滚 migrations,通过使用 revert 方法:
require_relative '2012121212_example_migration'
classFixupExampleMigration < ActiveRecord::Migration defchange revert ExampleMigration
create_table(:apples) do|t| t.string :variety end end end |
revert 方法也接受一系列的指令用来恢复。这变得很有用,用于恢复被选中的一些先前的 migrations。例如,让我们来想象一下,ExampleMigration 被提交了,最好是能找到替代的来序列化产品列表,这可以稍后来决定。可以这样写:
classSerializeProductListMigration < ActiveRecord::Migration defchange add_column :categories, :product_list
reversible do|dir| dir.up do # transfer data from Products to Category#product_list end dir.down do # create Products from Category#product_list end end
revert do # copy-pasted code from ExampleMigration create_table :productsdo|t| t.references :category end
reversible do|dir| dir.up do #add a foreign key execute <<-SQL ALTERTABLEproducts ADDCONSTRAINTfk_products_categories FOREIGNKEY(category_id) REFERENCEScategories(id) SQL end dir.down do execute <<-SQL ALTERTABLEproducts DROPFOREIGNKEYfk_products_categories SQL end end
# The rest of the migration was ok end end end |
同样的 migration 能够不使用 revert 来编写,但这将会涉及到更多的一些细节:恢复的顺序,create_table 和 reversible,用 drop_table 来替代 create_table,最终用 down 来替代 up 反之亦然。这些都是 revert 所需要注意的。
original url: http://guides.rubyonrails.org/migrations.html#writing-a-migration