如何用Rails添加一个列

100 阅读2分钟

简介

假设你有一个名为 "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。

我们只关心 "书籍 "表。

让我们来显示它。

Inside Books Table

书籍表内部

奖励:检查创建的表 - 如果使用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添加一个列很容易,我想说的是,重要的是要知道发生了什么,以及为什么。