Skip to content

Ruby on Rails - 迁移

Ruby on Rails - 数据库迁移 (Migrations)

Section titled “Ruby on Rails - 数据库迁移 (Migrations)”

Rails Migrations 是一种管理数据库模式随时间变化的方式。您不是直接编写 SQL DDL (数据定义语言),而是使用 DSL (领域特定语言) 在 Ruby 中定义模式变更。这使得您的模式变更(大部分情况下)与数据库无关,并且可以随应用程序代码一起进行版本控制。

使用迁移的好处:

  • 协作:如果一个开发者进行了模式变更,其他开发者可以通过运行 rails db:migrate 更新其本地数据库。
  • 部署:简化了部署过程中更新生产数据库模式的过程。
  • 版本控制:模式变更成为您代码库的一部分,并在版本控制(例如 Git)中被跟踪。
  • 数据库独立性:迁移抽象化了许多特定于数据库的 SQL 语法。
  • create_table(name, options):创建新表。
  • drop_table(name):删除表。
  • rename_table(old_name, new_name):重命名表。
  • add_column(table_name, column_name, type, options):向表中添加新列。
  • rename_column(table_name, old_column_name, new_column_name):重命名现有列。
  • change_column(table_name, column_name, type, options):更改列的类型或选项。
  • remove_column(table_name, column_name, options):删除列。
  • add_index(table_name, column_name_or_columns, options):向一个或多个列添加索引。
  • remove_index(table_name, options_or_column_name):删除索引。
  • add_reference(table_name, ref_name, options) 或 add_belongs_to:添加外键引用。
  • t.timestamps:在 create_table 块内的一个辅助方法,添加 created_at 和 updated_at 列。

迁移中支持的数据类型:

  • :string(用于短文本,例如标题)
  • :text(用于长文本,例如描述)
  • :integer(用于整数)
  • :bigint(用于更大的整数)
  • :float(用于浮点数)
  • :decimal(用于精确的小数,常用于货币)
  • :datetime(用于日期和时间)
  • :timestamp(类似于 datetime)
  • :date(仅用于日期)
  • :time(仅用于时间)
  • :binary(用于二进制数据)
  • :boolean(用于布尔值 true/false)

常见列选项::limit, :precision, :scale(用于 decimals),:default, :null(布尔值),:index(布尔值或选项哈希)。

您可以使用 rails generate migration 命令生成迁移文件。Rails 在文件名中使用时间戳来确保迁移按顺序运行。

示例:为我们的 books 和 subjects 表生成迁移(如果尚未通过 rails g model 生成):

$ bin/rails generate migration CreateBooks title:string price:decimal:10,2 subject_id:bigint:index description:text published_at:date
$ bin/rails generate migration CreateSubjects name:string:uniq

这会创建类似 db/migrate/YYYYMMDDHHMMSS_create_books.rb 和 db/migrate/YYYYMMDDHHMMSS_create_subjects.rb 的文件。

如果您使用 rails generate model Book title:string ...,迁移会自动创建。上面的示例展示了如何独立创建迁移。请注意 :index 会在 subject_id 上创建索引,:uniq 会在 subjects 表的 name 列上创建唯一索引。

让我们看看一个生成的(或手动创建的)迁移文件的内容。对于 CreateBooks:

db/migrate/YYYYMMDDHHMMSS_create_books.rb
class CreateBooks < ActiveRecord::Migration[7.0] # 使用您当前的 Rails 版本
def change
create_table :books do |t|
t.string :title, null: false
t.decimal :price, precision: 10, scale: 2
# t.references :subject, null: false, foreign_key: true # 添加外键的推荐方式
t.bigint :subject_id # 如果不使用 t.references
t.text :description
t.date :published_at
t.timestamps # 添加 created_at 和 updated_at 列
end
# 如果不使用带有 index: true 的 t.references,或者 subject_id 是手动添加的,则单独添加索引
add_index :books, :subject_id unless index_exists?(:books, :subject_id)
add_index :books, :title # 示例:在 title 列上添加索引
end
end

对于 CreateSubjects:

db/migrate/YYYYMMDDHHMMSS_create_subjects.rb
class CreateSubjects < ActiveRecord::Migration[7.0]
def change
create_table :subjects do |t|
t.string :name, null: false
t.timestamps
end
add_index :subjects, :name, unique: true unless index_exists?(:subjects, :name, unique: true)
end
end
  • ActiveRecord::Migration[7.0] 指定了此迁移是为哪个 Rails 版本编写的。
  • change 方法用于 Active Record 知道如何自动回滚的迁移(例如,create_table 可以通过 drop_table 回滚)。
  • 对于不可回滚的变更,您需要定义单独的 up(应用变更)和 down(回滚变更)方法。
  • t.timestamps 是一个辅助方法,添加 created_at 和 updated_at 列,Active Record 会自动管理它们。
  • null: false 使该列在数据库层面成为必需项。
  • t.references :subject, foreign_key: true 是一种便捷方式,用于添加 subject_id 列,并在其上添加索引和外键约束。

重要:避免将数据填充(例如 Subject.create(...))放在迁移文件中。迁移用于模式变更。数据填充应放在 db/seeds.rb 或自定义 Rake 任务中。

要将待处理的迁移应用到您的开发数据库:

$ bin/rails db:migrate

Rails 会在 schema_migrations 表中跟踪哪些迁移已经运行。此命令只会运行尚未运行的迁移。

其他有用的迁移命令:

  • bin/rails db:rollback:回滚上一次迁移。
  • bin/rails db:rollback STEP=3:回滚最近 3 次迁移。
  • bin/rails db:migrate:status:显示所有迁移的状态(已运行或未运行)。
  • bin/rails db:migrate VERSION=YYYYMMDDHHMMSS:向上或向下迁移到指定版本。
  • bin/rails db:schema:load:从 db/schema.rb 加载模式到当前环境的数据库(破坏性操作,会丢弃现有表)。对于快速设置新数据库非常有用。
  • bin/rails db:seed:运行 db/seeds.rb 文件。

要为特定环境(例如生产环境)运行迁移,请设置 RAILS_ENV 环境变量:

$ RAILS_ENV=production bin/rails db:migrate

在定义并迁移了数据库模式之后,您现在可以专注于构建控制器和视图,让用户与应用程序的数据进行交互了。