简介
假设你有一个名为 "books "的表,和一个名为 "Book "的相关模型。
你想添加 "作者 "这一列。
本教程中使用的工具:Rails 6.1.3, Ruby 3
请注意,这篇文章在任何版本的Rails或Ruby中都应该很好用。
简单回答
对于那些已经了解Rails的人来说,这里有一个简短的答案。
insidedb/migrate/20210131201926_add_author_to_books.rb
class AddAuthorToBooks < ActiveRecord::Migration[6.1]
def change
add_column :books, :author, :string
end
end
然后在你项目的根部运行bin/rails db:migrate 。
完整的教程
安装新的最小应用程序
在本教程中,我们不需要一个完整的Rails应用,只需要最低限度的应用就够了。从Rails 6.1开始,当你创建一个新的Rails应用时,可以使用--minimal标志。
$> rails _6.1.3_ new myapp --minimal
$> cd myapp
默认情况下,Rails将使用一个名为SQLite3的内存数据库。
题外话如果你想从PostgreSQL开始,你可以输入以下命令。
$> rails _6.1.3_ new myapp --minimal --database=postgresql
$> cd myapp
创建数据库
$/myapp> bin/rails db:create
Created database 'myapp_development'
Created database 'myapp_test'
创建第一个模型
$/myapp> bin/rails generate model Book title:string body:text
注意,"bin/rails "将使用为当前应用程序安装的rails二进制文件,而不是全局可用的。
这将创建许多文件。
invoke active_record
create db/migrate/20210331122059_create_books.rb
create app/models/book.rb
invoke test_unit
create test/models/book_test.rb
create test/fixtures/books.yml
你可能不需要所有的东西。有趣的是在db/migrate/20210131201925_create_books.rb 下创建的迁移文件(时间戳代表文件创建的当前时间,当然你会有比这个例子更多的时间)。
class CreateBooks < ActiveRecord::Migration[6.1]
def change
create_table :books do |t|
t.string :title
t.text :body
t.timestamps
end
end
end
然后运行迁移程序
$/myapp> bin/rails db:migrate
== 20210131201925 CreateBooks: migrating ======================================
-- create_table(:books)
-> 0.0019s
== 20210131201925 CreateBooks: migrated (0.0020s) =============================
添加一个迁移文件
创建一个名为db/migrate/20210131201926_add_column_to_books.rb的文件。
检查时间戳,它必须比之前创建的20210131201925_create_books.rb的数字要大。否则迁移文件将无法按照正确的顺序运行。
class AddColumnToBooks < ActiveRecord::Migration[6.1]
def change
add_column :books, :author, :string
end
end
迁移文件的分析
我们已经看到了时间戳。现在是迁移的名称:实际上它可以是任何东西。但是为了你自己或者其他开发者,尽量让意图明确:在这里我把add_column_to_books ,一个更好的名字可以是add_author_to_books 。总之,要确保文件名(除了时间戳之外)与类名相同。
现在我们继承了ActiveRecord::Migration,原因相当明显:我们要迁移数据,这是一个相当常见的行为,常见到可以隐藏在一个标准的Rails对象ActiveRecord::Migration里面。
数字表示Rails版本的前2个数字。这里我使用Rails 6.1.3,因此这两个数字是[6.1]。这是因为在ActiveRecord::Migration[6.1]中可能有一些功能是ActiveRecord::Migration[6.0]中没有的。
然后是 "改变 "方法。你不能(咳咳)改变名称,因为当你运行bin/rails db:migrate ,这个方法会被自动调用。
最后,add_column ,非常清楚:第一个参数是表的名称,然后是列的名称,然后是列的种类。
迁移数据
bin/rails db:migrate 将实际添加列到你当前的数据库中。
$/myapp> bin/rails db:migrate
== 20210131201926 AddColumnToBooks: migrating =================================
-- add_column(:books, :author, :string)
-> 0.0021s
== 20210131201926 AddColumnToBooks: migrated (0.0022s) ========================
检查schema.rb文件
你可以看到在你的schema.rb文件中,该列已经被添加到这里。
ActiveRecord::Schema.define(version: 20210131201926) do
create_table "books", force: :cascade do |t|
t.string "title"
t.text "body"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.string "author"
end
end
添加的列出现在这里。 t.string "author"
迁移 "出现 "在另一个地方:时间戳。请看ActiveRecord::Schema.define(version: 20210131201926) 。这个时间戳是你的迁移文件的时间戳。
奖励:检查创建的表 - 如果使用的是PostgreSQL
如果你使用了默认的SQLite3,请阅读下一段。如果你选择了PostgreSQL,这一段就对了 :)
在Rails中,你可以通过输入命令来检查实际的数据库。
$/myapp> bin/rails db
psql (13.1)
Type "help" for help.
myapp_development=#
很好 !你刚刚进入了PostgreSQL的命令行界面(CLI)。
myapp_development=# \dt
List of relations
Schema | Name | Type | Owner
--------+----------------------+-------+-------
public | ar_internal_metadata | table | shino
public | books | table | shino
public | schema_migrations | table | shino
(3 rows)
很好!你刚刚进入了PostgreSQL的命令行界面(CLI)。你可能注意到,Rails默认创建了2个表:ar_internal_metadata,以及schema_migrations。
我们只关心 "书籍 "表。
让我们来显示它。

书籍表内部
奖励:检查创建的表 - 如果使用SQLite3的话
这与上面的段落相同,但该命令只适用于SQLite3数据库(这是Rails默认的数据库)。
$/myapp> bin/rails db
SQLite version 3.28.0 2019-04-15 14:49:49
Enter ".help" for usage hints.
sqlite>
然后,显示表
sqlite> .headers on
sqlite> .mode columns
sqlite> .table
ar_internal_metadata books schema_migrations
然后,显示 "书籍 "表的内部信息。
sqlite> PRAGMA table_info('books');
cid name type notnull dflt_value pk
---------- ---------- ---------- ---------- ---------- ----------
0 id integer 1 1
1 title varchar 0 0
2 body text 0 0
3 created_at datetime(6 1 0
4 updated_at datetime(6 1 0
5 author varchar 0 0
神奇的方法:生成迁移
另一种可能性是使用脚手架,但在这种情况下,你必须特别注意文件的命名。
$/myapp> bin/rails generate migration AddAuthorToBooks author:string
或
$/myapp> bin/rails generate migration add_author_to_books author:string
迁移文件将被自动填入所有正确的值,包括时间戳。
在日常工作中,我并不使用这个魔法。我只是简单地复制/粘贴其他的迁移文件,注意文件的名称,仅此而已。
总结
用Rails添加一个列很容易,我想说的是,重要的是要知道发生了什么,以及为什么。