Rails 数据库迁移.docx_第1页
Rails 数据库迁移.docx_第2页
Rails 数据库迁移.docx_第3页
Rails 数据库迁移.docx_第4页
Rails 数据库迁移.docx_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Rails 数据库迁移(Migrations)数据库迁移(Migrations)提供了一些便利的方法让你有条理地修改数据库。虽然说直接 编写SQL也能修改数据库,但是这样你不但必须通知其他的开发者去执行一样的步骤,而且你 也得一直注意下次部署的时候和在正式上线的产品版服务器上面追踪并执行这些操作。Active Record 会自动追踪哪些 Migrations 已经执行过、哪些还没执行。所以,你只要更新 你本地的代码然后执行rake db:migrate,其他的就交给 Active Record ,它会自己搞懂该 跑哪些 Migrations 。还有,它也会自动更新db/schema.rb文件,让它与修改后的数据库结构同步。有了 Migrations ,你就可以用Ruby来写这些数据库变更。一件很棒的事情是 Migration 是独立 于数据库系统的(和大多数 Active Record 的功能一样),也就是说,你不用烦恼各种数据 库的语法差异,像是SELECT *的各种写法之类的。(当然,如果要针对某个特定的数据库 系统编写特定的功能的话,你也可以直接编写原始的SQL语句)。例如,你可以在开发阶段 使用SQLite3,在正式上线阶段则使用MySQL,它会自动处理好两者间的语法细节。在这个指南中,你将会了解到: 用于创建migration的生成器 Active Record 所提供用于操纵数据库的方法 用于操纵migrations的Rake任务 Migrations跟数据库纲要文件(schema.rb)的关联1 剖析迁移任务的构造在我们深入介绍migration的细节之前,我们先看下列例子,了解我们能怎么写 迁移任务:class CreateProducts ActiveRecord:Migrationdef upcreate_table :products do |t|t.string :namet.text :descriptiont.timestampsendenddef downdrop_table :productsendend这个迁移任务建立了一张叫products的数据库表,这张表中包含一个名为name的 string 类型字段和一个名为description的 text 类型字段。与此同时,一个名为id的字段也会被添加,这个字段是默认添加,我们不需要另外请求。另外 Active Record 所需要的时间戳( timestamp )字段( created_at 和 updated_at )也会被自动添加。而要取消这个任务只需简单地把这张表删除掉即可。数据迁移不仅可以胜任修改数据库架构,你还可以用它来修复数据库中的错误数据或者添加新字段。class AddReceiveNewsletterToUsers falseendUser.update_all :receive_newsletter = trueenddef downremove_column :users, :receive_newsletterendend在迁移任务中使用 Models 的一些警告:#using-models-in-your-migrations这个迁移为users表添加了一个receive_newsletter字段,并设定新的 user 创建 时它的默认值为false,对于数据库中已存在的 users 我们使用 User 模型来把他们的这个 标志位设为 true。Rails 3.1 为数据迁移提供了change方法使它变得更精简。这个方法主要用于一 些构造性的migrations(例如添加新字段或者新的表),它能知道怎么样迁移你的数据库 并在你需要回滚的时候恢复回去而并不需要写一个分开的down方法。class CreateProducts falseend不过,这样就失去了不同数据库系统之间的通用性。2 创建一个迁移任务2.1 建立一个 ModelModel和 scaffold的generators(生成器)在新建model的时候会自动生成对应的migration。 这个migraion里已经把建立数据表的步骤都写好了。如果生成的时候告诉Rails需要哪些字 段,Rails会把新增字段的代码都一起生成好。例如执行以下代码$ rails generate model Product name:string description:text将会生成的迁移任务如下:class CreateProducts ActiveRecord:Migrationdef changecreate_table :products do |t|t.string :namet.text :descriptiont.timestampsendendend如果有需要的话你可以追加更多的名称/类型字段。默认会生成的迁移任务都会包含t.timestamps(这个会生成updated_at和created_at字段,而 Active Record 会在 新增数据和更新时自动更新时间)。2.2 建立一个独立的迁移任务如果你建立迁移任务不是为了新增 Model,而是为了其他目的(例如为现在的数据库表添加 字段),那可以只用迁移任务的生成器:$ rails generate migration AddPartNumberToProducts这样会建立一个空白的但已经命名好的迁移任务:class AddPartNumberToProducts ActiveRecord:Migrationdef changeendend如果迁移任务的文件名命名为AddXXXToYYY或RemoveXXXFromYYY这类格式,后面再加上 一串字段名和类型的清单,那么这个migration就会含有对应的add_column和remove_column语句。$ rails generate migration AddPartNumberToProducts part_number:string将会生成:class AddPartNumberToProducts ActiveRecord:Migrationdef changeadd_column :products, :part_number, :stringendend类似的,$ rails generate migration RemovePartNumberFromProducts part_number:string则生成:class RemovePartNumberFromProducts ActiveRecord:Migrationdef upremove_column :products, :part_numberenddef downadd_column :products, :part_number, :stringendend这种方法可以操作多个字段,例如:$ rails generate migration AddDetailsToProducts part_number:string price:decimal将会生成:class AddDetailsToProducts falseend第二种格式,就是所谓的sexy写法,把 column 去掉了,用string和integer等方法来 建立对应类型的字段。至于在后面添加的参数是一样的。create_table :products do |t|t.string :name, :null = falseend默认在create_table时新增的主键名为id,要改主键的名称,你需要加上:primary_key这个选项(不要忘了更新对应 Model 的格式)。如果你根本就不要主键(例如使用多对多连接 HABTM的数据表时),那就传入:id = false。另外,如果要传入某个特定数据表的设定, 你可以在:options选项中加上一个SQL片段。例如:create_table :products, :options = ENGINE=BLACKHOLE do |t|t.string :name, :null = falseend这样在建立数据表的SQL语句中就会加入ENGINE=BLACKHOLE。(如果是用 MySQL 的话,预设 是ENGINE=InnoDB)3.2 创建连接表迁移任务的create_join_table方法可以创建一张多对多的连接表,经典的写法如下:create_join_table :products, :categories这里创建了一张名为categories_products的连接表,里面包含category_id和product_id这两个字段。你可以通过:table_name字段去定义自己想要的数据表名称。例如:create_join_table :products, :categories, :table_name = :categorization这里将会创建一张名为categorization的数据表。默认情况下,create_join_table将会创建两个不包含参数的字段,不过你也可以通过:column_options来指定这些参数。例如:create_join_table :products, :categories, :column_options = :null = true这里将会创建允许为空的product_id和category_id字段。3.3 变更数据表要变更现有的数据表,可以用create_table的类似方法change_table。它的用法跟create_table差不多,但它的代码块有更多的方式。例如:change_table :products do |t|t.remove :description, :namet.string :part_numbert.index :part_numbert.rename :upccode, :upc_codeend移除了两个字段description和name,创建了一个part_number的字符串类型字段并 为其添加了索引。最后重命名了upccode字段。3.4 特殊方法有些功能很常用,例如created_at和updated_at字段,为此,Active Record 提供了一 些捷径:create_table :products do |t|t.timestampsend以上会建立一个新的名为 products 数据表,并包含created_at和updated_at字段(当然还有id)。 此外:change_table :products do |t|t.timestampsend则会在原来的数据表中加入这两个字段。另一个特殊的方法是references(也可以写成belongs_to)。它最基本的的功能就是 增加可读性。create_table :products do |t|t.references :categoryend以上会建立一个category_id的字段,并给它一个适当的类型。要注意这里要输入的是model 的名称而不是字段名。Active Record 会自动在model名称的后面加上_id。若你需要用到 多态的belongs_to关联时,那么references会把两个所需的字段都加进去。create_table :products do |t|t.references :attachment, :polymorphic = :default = Photoend以上会建立一个attachment_id字段和一个默认值为Photo的attachment_type字段。references同时允许你直接定义索引而不用另外在create_table中执行add_index方法:create_table :products do |t|t.references :category, :index = trueend以上将会创建一个索引,跟 add_index :products, :category_id 所做的一样。references辅助方法实际上不会帮你建立外键约束。你可能需要通过execute方法 或者用能够加入外键支持:#7 的插件。如果Active Record提供的辅助方法不能满足你的需求,你可以使用execute方法来执行任意 的SQL语句。要想知道各个方法的细节和范例,请参考API文档,特别是关于ActiveRecord:ConnectionAdapters:SchemaStatements(提供了在up和down中可使用的方法)、ActiveRecord:ConnectionAdapters:TableDefinition(提供了在create_table所产生的对象中可使用的方法)、以及ActiveRecord:ConnectionAdapters:Table(提供了在create_table所产生的对象中可使用的方法)。3.5 使用change方法在一些情况下,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方法。3.6 使用up/down方法Migration里面的down方法能复原up方法所造成的变更。也就是说如果执行了up然后 再执行down,那么数据库的schema应该会没有改变。所以说,如果用up建立一个数据表, 就应该在down方法中删除它。明智的做法会使用跟up完全相反的顺便来做这些事情。 例如,class ExampleMigration ActiveRecord:Migrationdef upcreate_table :products do |t|t.references :categoryend#add a foreign keyexecute -SQLALTER TABLE productsADD CONSTRAINT fk_products_categoriesFOREIGN KEY (category_id)REFERENCES categories(id)SQLadd_column :users, :home_page_url, :stringrename_column :users, :email, :email_addressenddef downrename_column :users, :email_address, :emailremove_column :users, :home_page_urlexecute 0.0028s= CreateProducts: migrated (0.0028s) =想要控制这些输出值的话可以使用这几种方法:MethodPurposesuppress_messages阻止这个代码块的任何输出结果say输出一段文字(第二个参数可以指定是否要缩排)say_with_time输出一段文字,以及这个代码块需要花多少时间才能跑完。如果代 码块中回传了一个整数,这个数代表受影响的数据(rows)有多少。例如以下这个migrationclass CreateProducts and an index!- Waiting for a while- 10.0013s- 250 rows= CreateProducts: migrated (10.0054s) =如果你希望Active Record不作任何输出,那么执行rake db:migrate VERBOSE=false就可 以阻止所有的输出结果。5 在Migrations中使用Models在migration中不管你是新增数据或者更新数据,多少都会用到一个model。毕竟model存在 就是为了方便地处理我们的数据。这当然是没问题的,只是有些地方需要留意一下。比方说,当model使用不正确的数据库的字段或者使用的字段是后来的migration创建的时候 就会出现问题。根据这个例子,当爱丽比和鲍勃在同一份代码上工作,这份代码包含一个Product的模型:鲍勃正在放假期。爱丽丝创建了一个migration给products表添加一个新的字段并为它初始化。她同时在Product模型为这个新的字段添加了验证(validation)。# db/migrate/20100513121110_add_flag_to_product.rbclass AddFlagToProduct false)endendend# app/model/product.rbclass Product trueend爱丽丝又添加了一个migration来添加和初始化另一个字段并同样在model中添加了验证。# db/migrate/20100515121110_add_fuzz_to_product.rbclass AddFuzzToProduct fuzzyendendend# app/model/product.rbclass Product trueend这两个migrations在爱丽丝用起来是可以正常工作的。鲍勃从他的假期回来后他做了以下操作:1. 更新源代码 包含了艾丽丝添加的那两个migrations和最新版本的Product model。2. 执行rake db:migrate命令来执行还未执行的migrations(包含那个更新productmodel 的migration)。Migration执行失败,因为当model尝试保存的时候它会去验证那两个新增加的字段,而这些 字段在第一个migration执行的时候还没有添加数据库。rake aborted!An error has occurred, this and all later migrations canceled:undefined method fuzz for #对于这种情况可以尝试在migration中建立一个本地的model来修复。这样避免了validations 的执行,因此这个migration可以完成。当使用假的(faux)model时,我们可以直接调用Product.reset_column_information来更新ActiveRecord中Product模型的缓存从而在数据库中更新数据。如果爱丽丝能这样做,那么将不会有问题发生。# db/migrate/20100513121110_add_flag_to_product.rbclass AddFlagToProduct ActiveRecord:Migrationclass Product false)endendend# db/migrate/20100515121110_add_fuzz_to_product.rbclass AddFuzzToProduct ActiveRecord:Migrationclass Product fuzzy)endendend6 导出数据库纲要(Schema Dumping)6.1 Schema文件的作用?虽然我们用Migrations来定义database schema(数据库纲要),但是我们却不能一次看到完 整精确的schema。这个机制是由db/schema.rb或是Active Record检验数据库后所生成的 SQL文件来担当。它们设计出来不是用来编辑的,只是纯粹代表着数据库的schema现况。当我们要部署新的应用程序时,并不需要把整个migrations历程全部重跑一遍,我们只需要 把当前的schema载入新的数据库就可以了。这样做会更快更简单。例如,这就是建立一个测试用数据库所做的操作:把当前开发环境下的数据库导出来( 看是db/schema.rb或db/development.sql都行),然后再载入到测试数据库。另外,如果要快速浏览Active Record 对象中有哪些属性也可以通过schema文件。关于 Active Record对象属性的信息并不在model的代码中,而且可能会散布在多个migrations 之间,但是最终都会整理在schema文件中。其次,有个插件叫做annotate_models:/ctran/annotate_models , 可以把schema的结果自动用注释的方式放在每个model的上面,有需要也可以看一下。6.2 数据库纲要(Schema)的导出类型导出的schema有:sql和:ruby两种方式,可以通过config/application.rb文件中的config.active_record.schema_format来设置。如果设定成:ruby的话,schema就会存在db/schema.rb里面。这个文件看起来像是一个 超大的migration。ActiveRecord:Schema.define(:version = 20080906171750) docreate_table authors, :force = true do |t|t.string namet.datetime created_att.datetime updated_atendcreate_table products, :force = true do |t|t.string namet.text descriptiont.datetime created_att.datetime updated_att.string part_numberendend各方面来说,它也的确如此。这个文件的生成方式,正是在检查数据库并用create_table、add_index等方法,来表达数据库的结构。由于schema是独立于数据库系统的,只要是 Active Record支持的数据库系统,它都可以载入。如果你的应用程序要发布到多个数据库 系统,这点会非常有用。不过,这也是有考量的:db/schema.rb没办法表达出特定数据库所专属的功能,像是外键 约束(foreign key constraints)、触发(triggers)或是预存

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论