Rails开发细节《五》Migrations 数据迁移

简介:

Rails开发细节《五》Migrations 数据迁移

1.简介

在rails中用migration可以很方便的管理数据库的结构。可以创建数据库,创建表,删除表,添加字段,删除字段,整理数据。

migration就是一系列的class,这些类都继承了ActiveRecord::Migration类。

 

 
  1. class CreateProducts < ActiveRecord::Migration 
  2.   def up 
  3.     create_table :products do |t| 
  4.       t.string :name 
  5.       t.column :description:text 
  6.       t.timestamps 
  7.     end 
  8.   end 
  9.  
  10.   def down 
  11.     drop_table :products 
  12.   end  
  13. end 

上面就是一个migration例子。up方法中的代码会在

rake db:migrate

之后执行。

down方法中的代码会在

rake db:rollback

之后执行。

t.timestamps会自动产生created_at和updated_at列。

还可以进行表结构修改。


 
 
  1. class AddReceiveNewsletterToUsers < ActiveRecord::Migration 
  2.   def up 
  3.     change_table :users do |t| 
  4.       t.boolean :receive_newsletter:default => false 
  5.     end 
  6.     User.update_all ["receive_newsletter = ?"true
  7.   end 
  8.   
  9.   def down 
  10.     remove_column :users:receive_newsletter 
  11.   end 
  12. end 

rails3.1之后产生了一个新的方法change,主要用来创建表和列,不用写一对up和down了,使用rake db:rollback回滚的时候数据库不用down方法也知道如何做了。

1.1.migration提供了很多的方法

  • add_column
  • add_index
  • change_column
  • change_table
  • create_table
  • drop_table
  • remove_column
  • remove_index
  • rename_column

如果想回滚migration对数据库造成的改变,可以使用rake db:rollback命令。

 

1.2.ActiveRecord支持的列类型

  • :binary
  • :boolean
  • :date
  • :datetime
  • :decimal
  • :float
  • :integer
  • :primary_key
  • :string
  • :text
  • :time
  • :timestamp

 

2.创建migration

2.1.创建model

rails generate model Product name:string description:text

创建的migration文件位于db/migrate目录,文件名称为yyyymmddmmss_create_products.rb。

 

 
  1. class CreateProducts < ActiveRecord::Migration 
  2.   def change 
  3.     create_table :products do |t| 
  4.       t.string :name 
  5.       t.text :description 
  6.   
  7.       t.timestamps 
  8.     end 
  9.   end 
  10. end 

 

2.2.创建单独的migration

 

 
  1. rails generate migration AddPartNumberToProduct 

 

 
 
  1. class AddPartNumberToProducts < ActiveRecord::Migration 
  2.   def change 
  3.   end 
  4. end 
 
指定列的名称
 
 
 
  1. rails generate migration AddPartNumberToProduct part_number:string 
 

 

 
   
  1. class AddPartNumberToProducts < ActiveRecord::Migration 
  2.   def change 
  3.     add_column :products:part_number:string 
  4.   end 
  5. end 
删除列
 
 
  1. rails generate migration RemovePartNumberToProduct part_number:string 
 
 
 
 
  1. class RemovePartNumberFromProducts < ActiveRecord::Migration 
  2.   def up 
  3.     remove_column :products:part_number 
  4.   end 
  5.  
  6.   def down 
  7.     add_column :products:part_number:string 
  8.   end 
  9. end 
 
还可以添加多个列
 

 

 
 
  1. rails generate migration AddDetailsToProducts part_number:string price:decimal 
  2.  
  3.  
  4. class AddDetailsToProducts < ActiveRecord::Migration 
  5.   def change 
  6.     add_column :products:part_number:string 
  7.     add_column :products:price:decimal 
  8.   end 
  9. end 

3.编写mirgation

3.1.创建表

 

 
  1. create_table :products do |t| 
  2.  
  3.   t.string :name 
  4.  
  5. end 
  6.  
  7. create_table :products do |t| 
  8.  
  9.   t.column :name:string:null => false 
  10.  
  11. end 

 

如果数据库是mysql,还可以通过下面的语句指定使用的引擎,mysql默认的引擎是InnoDB。

 
 
  1. create_table :products:options => "ENGINE=MyISAM" do |t| 
  2.   t.string :name:null => false 
  3. end 

3.2.修改表结构

 

 
 
  1. change_table :products do |t| 
  2.   t.remove :description:name 
  3.   t.string :part_number 
  4.   t.index :part_number 
  5.   t.rename :upccode:upc_code 
  6. end 
 

删除name,description字段,添加part_number字段,在part_number字段建立索引,重命名upccode为upc_code。

3.3.辅助工具

t.timestamps可以自动添加created_at 和 updated_at列。

 

 

 
  
  1. #创建表的同时添加 
  2. create_table :products do |t| 
  3.   t.timestamps 
  4. end 
  5.  
  6. #给已经存在的表添加 
  7. change_table :products do |t| 
  8.   t.timestamps 
  9. end 

还有一个帮助工具references,用来指明表的外键关系。

 

 
 
  1. create_table :products do |t| 
  2.   t.references :category 
  3. end 

上面的代码会在products表中添加一个外键字段category_id。

 

 
  1. create_table :products do |t| 
  2.   t.references :attachment:polymorphic => {:default => 'Photo'
  3. end 

上面的代码不仅会在products表中添加外键字段attachment_id,还会添加attachment_type字段,string类型,默认值是Photo。

3.4.change方法的使用

change方法可以部分的替代up和down方法,数据库会自动的回滚。但是目前在change方法中只支持下面的migration。

  • add_column
  • add_index
  • add_timestamps
  • create_table
  • remove_timestamps
  • rename_column
  • rename_index
  • rename_table

如果要用其他的migration,你就需要自己写up和down了,不能再使用change了。

3.5.up和down方法的使用

down方法用来回滚数据库,你需要注意在down方法中的顺序,相对于up方法中的顺序。

 

 
  1. class ExampleMigration < ActiveRecord::Migration 
  2.   def up 
  3.     create_table :products do |t| 
  4.       t.references :category 
  5.     end 
  6.     #add a foreign key 
  7.     execute <<-SQL 
  8.       ALTER TABLE products 
  9.         ADD CONSTRAINT fk_products_categories 
  10.         FOREIGN KEY (category_id) 
  11.         REFERENCES categories(id) 
  12.     SQL 
  13.     add_column :users:home_page_url:string 
  14.     rename_column :users:email:email_address 
  15.   end 
  16.   
  17.   def down 
  18.     rename_column :users:email_address:email 
  19.     remove_column :users:home_page_url 
  20.     execute <<-SQL 
  21.       ALTER TABLE products 
  22.         DROP FOREIGN KEY fk_products_categories 
  23.     SQL 
  24.     drop_table :products 
  25.   end 
  26. end 

4.运行迁移

通过

 

 
  1. rake db:migrate 

命令就可以执行迁移任务。

如果指定了版本,就会执行指定版本的up,change或者down方法。版本就是migration文件的前缀。用VERSION参数来指定版本号。

 
  1. rake db:migrate VERSION=20080906120000 

拿上面的这个命令举例。如果20080906120000 比当前的版本大,会执行所有migration的up方法,包括20080906120000 中的up方法,不执行其他的migration方法。如果是小于,会执行所有migration的down方法,不包括20080906120000中的down方法。

4.1.回滚数据库

回滚上一次的数据库变更

rake db:rollback

回滚之前三次的数据库变更

rake db:rollback STEP=3

重做之前三次的数据库变更,重做之前会先回滚。

rake db:migrate:redo STEP=3

4.2.重置数据库

删除当前数据库,重新创建,重新执行migration。

 

 
  1. rake db:reset 

4.3.执行指定的migration

 
  1. rake db:migrate:up VERSION=20080906120000 

4.4.改变执行migration之后的提示信息

ethod Purpose
suppress_messages Takes a block as an argument and suppresses any output generated by the block.
say Takes a message argument and outputs it as is. A second boolean argument can be passed to specify whether to indent or not.
say_with_time Outputs text along with how long it took to run its block. If the block returns an integer it assumes it is the number of rows affected.

 

 
  1. class CreateProducts < ActiveRecord::Migration 
  2.   def change 
  3.     suppress_messages do 
  4.       create_table :products do |t| 
  5.         t.string :name 
  6.         t.text :description 
  7.         t.timestamps 
  8.       end 
  9.     end 
  10.     say "Created a table" 
  11.     suppress_messages {add_index :products:name
  12.     say "and an index!"true 
  13.     say_with_time 'Waiting for a while' do 
  14.       sleep 10 
  15.       250 
  16.     end 
  17.   end 
  18. end 

 

5.在migration中使用model对象

假设有两个开发者,公用一个代码库。

其中一个休假了,另外一个还在工作,对数据库进行了修改。

 

 
  1. # db/migrate/20100513121110_add_flag_to_product.rb 
  2.   
  3. class AddFlagToProduct < ActiveRecord::Migration 
  4.   def change 
  5.     add_column :products:flag:boolean 
  6.     Product.all.each do |product| 
  7.       product.update_attributes!(:flag => 'false'
  8.     end 
  9.   end 
  10. end 
  11.  
  12. # app/model/product.rb 
  13.   
  14. class Product < ActiveRecord::Base 
  15.   validates :flag:presence => true 
  16. end 
  17.  
  18. # db/migrate/20100515121110_add_fuzz_to_product.rb 
  19.   
  20. class AddFuzzToProduct < ActiveRecord::Migration 
  21.   def change 
  22.     add_column :products:fuzz:string 
  23.     Product.all.each do |product| 
  24.       product.update_attributes! :fuzz => 'fuzzy' 
  25.     end 
  26.   end 
  27. end 
  28.  
  29. # app/model/product.rb 
  30.   
  31. class Product < ActiveRecord::Base 
  32.   validates :flag:fuzz:presence => true 
  33. end 

添加了一些字段,添加了一些验证。

休假的同事回来了。

获取代码。

执行 rake db:migrate。

报错了。

 

 
  1. rake aborted! 
  2. An error has occurred, this and all later migrations canceled: 
  3.   
  4. undefined method `fuzz' for #<Product:0x000001049b14a0> 

因为在执行完第一个migration之后,验证model的时候,还没有执行第二个migration,也就还没有fuzz字段。

解决的办法就是在migration中添加空的model定义,阻止migration运行的时候验证model,因为空的model中没有验证规则,这样就migration就可以运行完毕。

由于在migration中包括更新字段的操作,还需要添加Product.reset_column_information来更新ActiveRecord中缓存的之前的空Product就可以了。

 

 
  1. # db/migrate/20100513121110_add_flag_to_product.rb 
  2.   
  3. class AddFlagToProduct < ActiveRecord::Migration 
  4.   class Product < ActiveRecord::Base 
  5.   end 
  6.   
  7.   def change 
  8.     add_column :products:flag:integer 
  9.     Product.reset_column_information 
  10.     Product.all.each do |product| 
  11.       product.update_attributes!(:flag => false
  12.     end 
  13.   end 
  14. end 
  15.  
  16.  
  17. # db/migrate/20100515121110_add_fuzz_to_product.rb 
  18.   
  19. class AddFuzzToProduct < ActiveRecord::Migration 
  20.   class Product < ActiveRecord::Base 
  21.   end 
  22.   
  23.   def change 
  24.     add_column :products:fuzz:string 
  25.     Product.reset_column_information 
  26.     Product.all.each do |product| 
  27.       product.update_attributes!(:fuzz => 'fuzzy'
  28.     end 
  29.   end 
  30. end 

 

6.数据库的描述文件

在 db/schema.rb或者是db/*.sql文件中就是数据库的结构,这个文件不是用来修改的,自动生成,用来查看数据库的当前状态。

6.1.描述文件的类型

在config/application.rb文件中可以配置描述文件的类型,config.active_record.schema_format,值为 :sql 或 :ruby,默认是:ruby。如果是:ruby,文件的内容就是。

 

 
  1. ActiveRecord::Schema.define(:version => 20080906171750) do 
  2.   create_table "authors":force => true do |t| 
  3.     t.string   "name" 
  4.     t.datetime "created_at" 
  5.     t.datetime "updated_at" 
  6.   end 
  7.   
  8.   create_table "products":force => true do |t| 
  9.     t.string   "name" 
  10.     t.text "description" 
  11.     t.datetime "created_at" 
  12.     t.datetime "updated_at" 
  13.     t.string "part_number" 
  14.   end 
  15. end 

 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/1019513,如需转载请自行联系原作者

目录
相关文章
|
11天前
|
存储 关系型数据库 MySQL
《MySQL 简易速速上手小册》第5章:高可用性和灾难恢复(2024 最新版)
《MySQL 简易速速上手小册》第5章:高可用性和灾难恢复(2024 最新版)
30 2
|
11天前
|
安全 关系型数据库 MySQL
《MySQL 简易速速上手小册》第4章:数据安全性管理(2024 最新版)
《MySQL 简易速速上手小册》第4章:数据安全性管理(2024 最新版)
32 3
|
8月前
|
前端开发 JavaScript Docker
用 Rails 开发 WebSSH(入门版)
用 Rails 开发 WebSSH(入门版)
|
10月前
|
运维 Devops 开发工具
bug怎样算修完,浅谈团队分布式bug管理 git-poison简单易用的bug管理工具
介绍基于go-git开发实现通用化的git-poison,通过分布式源码管理bug追溯、查询。
46325 16
|
12月前
|
运维 关系型数据库 MySQL
【荐书&赠书】MySQL技术大全开发、优化与运维实战
【荐书&赠书】MySQL技术大全开发、优化与运维实战
191 0
|
PHP 数据库
laravel数据迁移
laravel数据迁移
97 0
|
SQL 存储 安全
Sentry 开发者贡献指南 - 数据库迁移
Sentry 开发者贡献指南 - 数据库迁移
177 0
|
数据可视化 开发工具 数据库
史上最全的企业级项目管理工具之Yapi,禅道,GitLab 搭建
前言 文本已收录至我的GitHub仓库,欢迎Star:github.com/bin39232820… 种一棵树最好的时间是十年前,其次是现在
323 0
|
存储 NoSQL Linux
第2期 全栈开发MongoDB数据库安装
MongoDB是一个基于分布式文件存储的数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。
125 0
第2期 全栈开发MongoDB数据库安装
|
jenkins 持续交付 Windows
Jenkins +ThinBackup备份恢复插件(学习笔记三十四)
一、系统管理-管理插件-找到ThinBackup并安装 二、系统管理-找到ThinBackup-点击Setting进行设置 第一个参数备份目录是必选,其它可选,点保存。
2576 0