跳转到内容

Ruby on Rails/ActiveRecord/Migrations

来自 Wikibooks,开放世界的开放书籍

[1] 迁移旨在解决向数据库推出更改的问题。通过在 Ruby 文件中定义对数据库模式的更改,开发团队可以确保对数据库的所有更改都经过适当的版本控制。此外,迁移还有助于确保将更改推出给其他开发人员以及其他服务器(开发、QA、生产)以一致且可管理的方式进行处理。

构建迁移

[编辑 | 编辑源代码]

您可以使用以下方法独立构建迁移

ruby script/generate migration Category

并在之后编写特定的命令(如果您想创建自定义 SQL,这是最佳选择),或者您可以创建一个包含迁移的模型,使用以下方法:

ruby script/generate model Category name:string amount:integer

控制台告诉您创建了一些文件,而另一些文件已经存在。如前所述,Rails 永远不会覆盖现有文件,除非另有说明。

现在让我们看看迁移

# 20090409120944_create_categories.rb
class CreateCategories < ActiveRecord::Migration
  def self.up
    create_table :categories do |t|
      t.string :name
      t.integer :amount

      t.timestamps
    end
  end

  def self.down
    drop_table :categories
  end
end

首先,查看文件前面的数字(20090409120944)。这是您的文件的时间戳,对于创建数据库表非常重要。此时间戳始终不同,具体取决于创建迁移的确切时间。其背后的理念是拥有所有迁移的“历史记录”。

但为什么这很重要呢?

想象一下,您在一个 Rails 项目上工作,并且通过迁移创建表、更改列或从数据库中删除列。过了一段时间,您的客户改变了主意,他只想要非常基本的功能,而您已经开始创建高级功能并更改了数据库。因为您无法记住所有进入数据库的更改及其顺序,所以您要么花很多时间处理数据库以获得“旧”状态,要么您必须从头开始,因为记住并重做所有更改会花费太长时间。这就是迁移派上用场的地方,由于时间戳,Rails 能够以实际顺序识别更改,并且所有更改都可以轻松撤消。切勿手动更改时间戳。这肯定会导致问题。有关这些主题的更多信息,请查看“管理迁移”部分

说到撤消和重做:请注意迁移中的两个方法self.upself.down. 它们的功能完全相反。尽管self.up创建带有所有列的类别表,self.down从数据库中删除(删除)该表及其所有内容 (!!)。当 Rails 看到迁移尚未移动到数据库时,它将使用self.up方法,如果您撤消迁移,self.down方法将被执行。这样,您可以确保始终能够回到数据库的过去状态。请记住,在编写自己的迁移时,始终包含一个self.up和一个self.down方法以确保数据库状态在回滚后保持一致。

好的,让我们从迁移本身开始

create_table :categories do |t|
      t.string :name
      t.integer :amount
      t.timestamps
end

我们想要创建一个名为 categories 的表(create_table :categories) 它包含一个名称列和一个金额列。此外,Rails 为我们添加了一个时间戳,它将存储每行的创建日期和更新日期。Rails 还将创建一个名为model_id 的主键,它会随着每行的添加而自动递增 (1,2,3,...)。

您可以从多种与 ActiveRecord 匹配的数据类型中进行选择。最常见的类型是

  • string
  • text
  • integer
  • decimal
  • timestamp
  • references
  • boolean

但是等等,我们的数据库中还没有单个表或列。我们需要将迁移文件写入数据库。

rake db:migrate

负责这项工作。该命令能够创建该表以及该表中所有必要的列。此命令不仅限于迁移单个文件,因此您可以同时迁移无限数量的文件。Rake 还知道数据库中已经存在哪些迁移,因此它不会覆盖您的表。有关更多信息,请参阅“管理迁移”。

为了在表之间添加连接,我们想要在模型中添加引用。引用类似于外键(Rails 默认不使用外键,因为并非所有数据库都能处理外键,但您可以编写自定义 SQL 来使用外键),并告诉您的表在哪里查找更多数据。

让我们在已经存在的数据库中添加另一个模型。我们想要创建一个类别,该类别包含多个产品。因此,我们需要在类别中引用此产品。我们想要创建一个模型

ruby script/generate model Products name:string category:references

并将其插入数据库

rake db:migrate

请注意类别中的类型 :references。这告诉 Rails 在数据库中创建一个包含对类别的引用的列。现在,我们的数据库中有一个category_id用于产品的列。(为了使用这两个模型,我们需要在模型中添加关联,请参阅关联)

管理迁移

[编辑 | 编辑源代码]

我们已经讨论了迁移如何帮助您以非常方便的方式组织数据库。现在,我们将看看它是如何实现的。您已经知道文件名中的时间戳告诉 Rails 迁移是在何时创建的,并且 Rake 知道数据库中已经存在哪些迁移。

为了将数据库状态恢复到之前的样子,例如当前状态之前的 5 次迁移,我们可以使用以下命令

 $rake db:rollback STEP=5

这将撤消已提交到数据库的最后 5 次迁移。

要重做最后 5 步,我们可以使用类似的命令

 $ rake db:migrate:redo STEP=5

您也可以回滚或重做迁移状态的特定版本,只需提供时间戳即可

 $ rake db:migrate:up VERSION=20080906120000

选择是要执行 db_migrate:up 方法还是 db_migrate:down 方法

请记住,将数据库恢复到以前的状态将完全删除已经插入的数据!

模式方法参考

[编辑 | 编辑源代码]

以下方法可用于在 Ruby 中定义模式更改

  • create_table(name, options): 创建一个名为 name 的表,并使该表对象可用于添加列的代码块,其格式与add_column相同。请参阅上面的示例。options 哈希用于“DEFAULT CHARSET=UTF-8”之类的片段,这些片段将附加到创建表的定义中。
  • drop_table(name): 删除名为 name 的表。
  • rename_table(old_name, new_name): 将名为 old_name 的表重命名为 new_name。
  • add_column(table_name, column_name, type, options): 向名为 table_name 的表中添加一个名为 column_name 的新列,指定为以下类型之一::string、:text、:integer、:float、:datetime、:timestamp、:time、:date、:binary、:boolean。可以通过传递 options 哈希(例如 { :default => 11 })来指定默认值。
  • rename_column(table_name, column_name, new_column_name): 重命名列,但保留类型和内容。
  • change_column(table_name, column_name, type, options): 使用与add_column.
  • remove_column(table_name, column_name): 从名为 table_name 的表中删除名为 column_name 的列。
  • add_index(table_name, column_names, index_type, index_name): 在列(或 index_name(如果指定)上)添加一个新索引,其名称为列名。指定可选的 index_type(例如 UNIQUE)。
  • remove_index(table_name, index_name): 删除由 index_name 指定的索引。

命令参考

[编辑 | 编辑源代码]
  • rake db:create[:all]: 如果没有指定 :all,则创建 config/database.yml 中定义的当前 RAILS_ENV 的数据库。 如果指定 :all,则创建 config/database.yml 中定义的所有数据库。
  • rake db:fixtures:load: 将 fixture 加载到当前环境的数据库中。 使用 FIXTURES=x,y 加载特定的 fixture
  • rake db:migrate [VERSION=n]: 通过 db/migrate 中的脚本迁移数据库。 使用 VERSION=n 针对特定版本
  • rake db:migrate:redo [STEP=n]: (2.0.2) 通过回滚“STEP”个版本的数量并重新应用迁移来回滚数据库。
  • rake db:migrate:reset: (2.0.2) 删除数据库,创建它,然后重新应用所有迁移。 rake db:create 注释中概述的注意事项适用。
  • rake db:reset: 使用 db/schema.rb 删除并重新创建数据库。 rake db:create 注释中概述的注意事项适用。
  • rake db:rollback [STEP=N]: (2.0.2) 将迁移回滚 1 或 n 个 STEP。
  • rake db:schema:dump: 创建一个 db/schema.rb 文件,该文件可以移植地用于 AR 支持的任何数据库
  • rake db:schema:load: 将 schema.rb 文件加载到数据库中
  • rake db:sessions:clear: 清除 sessions 表
  • rake db:sessions:create: 创建一个 sessions 表,用于与 CGI::Session::ActiveRecordStore 一起使用
  • rake db:structure:dump: 将数据库结构转储到 SQL 文件中
  • rake db:test:clone: 从当前环境的数据库模式重新创建测试数据库
  • rake db:test:clone_structure: 从开发结构重新创建测试数据库
  • rake db:test:prepare: 准备测试数据库并加载模式
  • rake db:test:purge: 清空测试数据库

您可以在任何时候使用以下命令获取命令列表:rake -T从您的应用程序的根目录中。

您可以使用以下命令获得每个任务的更完整描述:

rake --describe task:name:and:options

迁移的官方 API

  1. 摘录修改并从 Steve Eichert 的 Ruby on rails Migrations Explained 文章中重新发布。
华夏公益教科书