宁皓网的付费会员可以查看课程:《Rails:数据库 Migration》http://ninghao.net/course/4133
创建 Migration
使用命令行:
rails generate migration 名字
简写:
rails g migration 名字
migration 的名字要描述清楚它的作用,使用驼峰式的名字,创建的 migration 会包含一个时间,它会作为数据库的版本,Rails 也会用这个时间来判断哪些是执行过的 migration 。执行的 migration 会记录在数据库里。
现在我要创建一个 migration,可以帮助我们在数据库里创建一个数据表:
rails generate migration CreateArticles
返回的东西像这样:
Running via Spring preloader in process 607 invoke active_record create db/migrate/20160927082426_create_articles.rb
migration 文件会保存在 db/migrate 目录的下面,文件的名字里 20160927082426 是创建这个 migration 的时间。打开这个 migration:
class CreateArticles < ActiveRecord::Migration[5.0] def change create_table :articles do |t| end end end
一个 migration 就是一个类,默认它里面定义了一个 change 方法,在这个方法里,这个 migration 使用了 create_table 方法,创建了一个名字是 :articles 的数据表。rails 根据我们在创建这个 migration 的时候使用的名字推断我们是要创建一个可以创建名字是 articles 数据表的 migration。
运行 Migration
使用命令:
rails db:migrate
输出:
== 20160927082426 CreateArticles: migrating =================================== -- create_table(:articles) -> 3.7057s == 20160927082426 CreateArticles: migrated (3.7066s) ==========================
这样就会真正的执行在 migration 里定义的动作。我们这里就是去在数据库里创建一个名字是 articles 的数据表。
SHOW TABLES; +---------------------------+ | Tables_in_app_development | +---------------------------+ | ar_internal_metadata | | articles | | schema_migrations | +---------------------------+
查看一下这个表:
DESCRIBE articles; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | +-------+---------+------+-----+---------+----------------+
新创建的这个数据表里面只有一个 id 字段,它是这个表的主键。
schema_migrations
再查看一下 schema_migrations 表:
SELECT * FROM `schema_migrations`; +----------------+ | version | +----------------+ | 20160927082426 | +----------------+
这个表只有一个 version,它表示数据库的版本,字段的值就是 migration 文件名字里的那个时间部分。这个表会记录已经执行了的 migration。
回滚 Migration
Rollback,回滚。它有点像是 migrate 的逆向操作。回滚最近一次做的 migrate,执行:
rails db:rollback
输出:
== 20160927084920 AddTitleToArticles: reverting =============================== -- remove_column(:articles, :title, :string) -> 5.5738s == 20160927084920 AddTitleToArticles: reverted (5.5813s) ======================
在输出的内容里,你会发现,执行了 remove_column 方法,它可以删除表里的字段,这里它把 articles 表里的 title 字段给删除掉了。add_column 的逆向操作就是 remove_column。
再查看一下 articles 表,你会发现之前添加的 title 字段已经不见了。在执行这个命令的时候可以加上一个 STEP 参数,它可以指定要回滚的次数。也就是去回滚最近几次做的 migrate 。
rails db:rollback STEP=3
redo
redo 就是先 rollback,然后再 migrate 一下。
rails db:migrate:redo
添加栏
再创建一个 migration,可以在 articles 表里添加一个 title 字段:
rails generate migration AddTitleToArticles title:string
输出:
Running via Spring preloader in process 625 invoke active_record create db/migrate/20160927084920_add_title_to_articles.rb
生成的 migration 是:
class AddTitleToArticles < ActiveRecord::Migration[5.0] def change add_column :articles, :title, :string end end
change 方法里用了 add_column 方法,它可以在指定的数据表里添加字段,Rails 已经为我们设置好了数据表的名字。
执行:
rails db:migrate
输出:
== 20160927084920 AddTitleToArticles: migrating =============================== -- add_column(:articles, :title, :string) -> 4.7404s == 20160927084920 AddTitleToArticles: migrated (4.7405s) ======================
查看数据库里的 articles 数据表:
DESCRIBE articles; +-------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(255) | YES | | NULL | | +-------+--------------+------+-----+---------+----------------+
表里有了新字段,名字是 title,类型是 varchar(string)。
再查看一下 schema_migrations 表里的记录:
SELECT * FROM schema_migrations`; +----------------+ | version | +----------------+ | 20160927082426 | | 20160927084920 | +----------------+
多了一条:20160927084920,它就是刚才我们添加了用来在 articles 表里添加 title 字段的那个 migration 的文件名字里的时间部分。
重命名表
创建一个可以重命名表的 migration:
rails generate migration RenameArticlesToPosts
输出:
Running via Spring preloader in process 701 invoke active_record create db/migrate/20160927101449_rename_articles_to_posts.rb
手工编辑一下生成的这个 migration:
class RenameArticlesToPosts < ActiveRecord::Migration[5.0] def change rename_table :articles, :posts end end
rename_table 方法可以重命名数据表。
执行:
rails db:migrate
返回:
== 20160927101449 RenameArticlesToPosts: migrating ============================ -- rename_table(:articles, :posts) -> 0.5636s == 20160927101449 RenameArticlesToPosts: migrated (0.5637s) ===================
查看:
SHOW TABLES; +---------------------------+ | Tables_in_app_development | +---------------------------+ | ar_internal_metadata | | posts | | schema_migrations | +---------------------------+
之前的 articles 表的名字,已经变成了 posts。
修改栏
先创建一个 migration,在 posts 表里添加一个新的字段 .. 名字是 content ,类型是 text。
rails generate migration AddContentToPosts content:text
migrate:
rails db:migrate
现在我们的 posts 表是:
DESCRIBE posts; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(255) | YES | | NULL | | | content | text | YES | | NULL | | +---------+--------------+------+-----+---------+----------------+
我要修改一下 content 字段的类型,创建一个 migration:
rails generate migration ChangeContentFromPosts
打开这个新创建的 migration,编辑一下:
class ChangeContentFromPosts < ActiveRecord::Migration[5.0] def change change_column :posts, :content, :string end end
修改字段用的是 change_column 方法,把 posts 表里的 content 字段的类型修改成了 string。
migrate:
rails db:migrate
输出:
== 20160927105001 ChangeContentFromPosts: migrating =========================== -- change_column(:posts, :content, :string) -> 5.7436s == 20160927105001 ChangeContentFromPosts: migrated (5.7438s) ==================
查看:
DESCRIBE posts; +---------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(255) | YES | | NULL | | | content | varchar(255) | YES | | NULL | | +---------+--------------+------+-----+---------+----------------+
观察 content 字段的类型的变化。
up/down
This migration uses change_column, which is not automatically reversible. To make the migration reversible you can either: 1. Define #up and #down methods in place of the #change method. 2. Use the #reversible method to define reversible behavior.
修改表
change_table 可以修改数据表里的字段。创建一个 migration 用一下这个方法:
rails generate migration ChangeDetailsFromPosts
修改:
class ChangeDetailsFromPosts < ActiveRecord::Migration[5.0] def change change_table :posts do |t| t.rename :content, :body t.timestamps end end end
在 change 方法里我们用了 change_table,修改了 posts 表里的一些东西,把 content 栏重命名成了 body,又添加了一个 timestamps,它会生成两个栏,created_at 与 updated_at 。
DESCRIBE posts; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(255) | YES | | NULL | | | body | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+
创建表
create_table 可以在数据库里创建数据表,创建一个数据表,名字是 users:
rails generate migration CreateUsers
创建的这个 migration 是这样的:
class CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| end end end
自动在 migration 里使用了 create_table 方法,修改一下这个 migration:
class CreateUsers < ActiveRecord::Migration[5.0] def change create_table :users do |t| t.string :user_name t.string :email t.timestamps end end end
migrate 一下以后,查看一下 users 数据表:
DESCRIBE users; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | user_name | varchar(255) | YES | | NULL | | | email | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+
添加关联
在 posts 表上添加一个到 user 的关联。
rails generate migration AddUserRefToPosts user:references Running via Spring preloader in process 91 invoke active_record create db/migrate/20160928005804_add_user_ref_to_posts.rb
这条命令里我们添加了一个 user:references,它会给我们在 posts 表里生成一个到 user 的关联。
class AddUserRefToPosts < ActiveRecord::Migration[5.0] def change add_reference :posts, :user, foreign_key: true end end
这个 migration 里用了 add_reference,在 posts 表上添加一个到 user 的关联。foreign_key 设置了外键。
DESCRIBE posts; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | title | varchar(255) | YES | | NULL | | | body | varchar(255) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | | user_id | int(11) | YES | MUL | NULL | | +------------+--------------+------+-----+---------+----------------+
migrate 一下。你可以使用 phpMyAdmin 或者 MySQL Workbench 去查看表之间的关联。你会发现,user_id 是 posts 表里的一个外键,它对应的是同数据库里的 users 表里的 id 字段的值。
栏修饰符
在创建或修改栏的时候可以使用一些修饰符。
limit
precision
scale
polymorphic
null
default
index
comment
关键词:“ rails column modifiers ”
比如现在我想修改 users 表里的 email 栏的长度,而且想给它添加一个默认的值。可以使用 change_column 方法,再加上 limit 这个修饰符。
创建一个 migration:
rails generate migration AlterEmailFromUsers Running via Spring preloader in process 133 invoke active_record create db/migrate/20160928015618_alter_email_from_users.rb
修改一下这个 migration:
class AlterEmailFromUsers < ActiveRecord::Migration[5.0] def change change_column :users, :email, :string, limit: 100 end end
migrate 以后,查看一下 users 表:
DESCRIBE users; +------------+--------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +------------+--------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | user_name | varchar(255) | YES | | NULL | | | email | varchar(100) | YES | | NULL | | | created_at | datetime | NO | | NULL | | | updated_at | datetime | NO | | NULL | | +------------+--------------+------+-----+---------+----------------+
注意 email 栏的长度的变化。
change
add_column
add_foreign_key
add_index
add_reference
add_timestamps
change_column_default
(要提供:from
与:to
选项)change_column_null
create_join_table
create_table
disable_extension
drop_join_table
drop_table
(必须提供一个代码块)enable_extension
remove_column
(必须提供类型)remove_foreign_key
(必须提供第二个表)remove_index
remove_reference
remove_timestamps
rename_column
rename_index
rename_table
reversible
自己定义 migrate 的时候执行的动作,还有对应的 rollback 的时候要执行的动作。
rails generate migration ReversibleDemo
修改:
class ReversibleDemo < ActiveRecord::Migration[5.0] def change reversible do |dir| dir.up do say "前进!" end dir.down do say "撤退!" end end end end
dir 表示方向,up 就是在 migrate 的时候执行的动作,down 就是在 rollback 的时候执行的动作。
migrate:
rails db:migrate == 20160928023555 ReversibleDemo: migrating =================================== -- 前进! == 20160928023555 ReversibleDemo: migrated (0.0002s) ==========================
rollback:
rails db:rollback == 20160928023555 ReversibleDemo: reverting =================================== -- 撤退! == 20160928023555 ReversibleDemo: reverted (0.0284s) ==========================
revert
恢复之前执行过的 migration。
rails generate migration RevertDemo
可以使用 revert,给它一个代码块:
class RevertDemo < ActiveRecord::Migration[5.0] def change revert do # 要恢复的动作 end say "重做!" end end
也可以导入之前创建的 migration:
require_relative '20160928023555_reversible_demo' class RevertDemo < ActiveRecord::Migration[5.0] def change revert ReversibleDemo say "重做!" end end
执行:
rails db:migrate == 20160928034734 RevertDemo: migrating ======================================= -- 撤退! -- 重做! == 20160928034734 RevertDemo: migrated (0.0073s) ==============================
Ruby
评论
路过。。。
8 年 1个月 以前
文章第一行就有错别字。皓哥太大意了哈哈。
8 年 1个月 以前
嘿嘿嘿,见笑了哈。
8 年 1个月 以前