1 Migration 概述
Migrations 是一種方便的方式 隨著時間的推移改變你的資料庫架構 以一致的方式。他們使用 Ruby DSL,因此您不必 手動編寫 SQL,允許您的架構和更改獨立於資料庫。
您可以將每個 migration 視為資料庫的新“版本”。一個
模式開始時什麼都沒有,每個 migration 都會修改它以新增或
刪除表、列或條目。 Active Record 知道如何更新您的
沿著這個時間線的模式,從它在
歷史記錄到最新版本。 Active Record 也會更新您的
db/schema.rb
檔案以匹配資料庫的最新結構。
下面是一個 migration 的例子:
class CreateProducts < ActiveRecord::Migration[7.0]
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
這個 migration 添加了一個名為 products
的表,其中有一個名為的字串列
name
和名為 description
的文字列。一個名為 id
的主要 key 列
也將被隱式新增,因為它是所有 Active 的預設主 key
記錄 models。 timestamps
宏添加了兩列,created_at
和
updated_at
。這些特殊列由 Active Record 自動管理
如果它們存在。
請注意,我們定義了我們希望及時發生的變化。 在此 migration 執行之前,將沒有表。之後,表將 存在。 Active Record 也知道如何反轉這個 migration:如果我們滾動 將此migration 返回,它將刪除表。
在支援 transactions 和更改架構的語句的資料庫上, migrations 被包裹在一個 transaction 中。如果資料庫不支援這個 那麼當 migration 失敗時,成功的部分將不會被滾動 背部。您將不得不回滾手動所做的更改。
有些查詢不能在 transaction 中執行。如果你的
介面卡支援 DDL transactions 你可以使用 disable_ddl_transaction!
來
為單個 migration 禁用它們。
如果你希望 migration 做一些 Active Record 不知道的事情
要反轉,您可以使用 reversible
:
class ChangeProductsPrice < ActiveRecord::Migration[7.0]
def change
reversible do |dir|
change_table :products do |t|
dir.up { t.change :price, :string }
dir.down { t.change :price, :integer }
end
end
end
end
或者,您可以使用 up
和 down
代替 change
:
class ChangeProductsPrice < ActiveRecord::Migration[7.0]
def up
change_table :products do |t|
t.change :price, :string
end
end
def down
change_table :products do |t|
t.change :price, :integer
end
end
end
2 建立一個 Migration
2.1 建立一個獨立的 Migration
Migration 以檔案的形式存放在 db/migrate
目錄中,每一個
migration 類。檔名的形式是
YYYYMMDDHHMMSS_create_products.rb
,即UTC時間戳
標識 migration 後跟下劃線後跟名稱
migration 的。 migration 類的名稱(CamelCased 版本)
應該匹配檔名的後半部分。例如
20080906120000_create_products.rb
應該定義類 CreateProducts
和
20080906120001_add_details_to_products.rb
應該定義
AddDetailsToProducts
。 Rails 使用這個時間戳來確定哪個 migration
應該以什麼順序執行,所以如果你從另一個複製 migration
應用程式或自己生成檔案,注意它在訂單中的位置。
當然,計算時間戳並不好玩,所以 Active Record 提供了一個 發電機為您處理製作:
$ bin/rails generate migration AddPartNumberToProducts
這將建立一個適當命名的空 migration:
class AddPartNumberToProducts < ActiveRecord::Migration[7.0]
def change
end
end
這個生成器可以做的不僅僅是在檔名上附加一個時間戳。 基於命名約定和附加(可選)引數,它可以 也開始充實 migration。
如果 migration 名稱的格式為“AddColumnToTable”或
“RemoveColumnFromTable”,後跟列名列表和
然後鍵入一個 migration 包含適當的 add_column
和
remove_column
語句將被建立。
$ bin/rails generate migration AddPartNumberToProducts part_number:string
會產生
class AddPartNumberToProducts < ActiveRecord::Migration[7.0]
def change
add_column :products, :part_number, :string
end
end
如果您想在新列上新增索引,您也可以這樣做。
$ bin/rails generate migration AddPartNumberToProducts part_number:string:index
將生成適當的 add_column
和 add_index
語句:
class AddPartNumberToProducts < ActiveRecord::Migration[7.0]
def change
add_column :products, :part_number, :string
add_index :products, :part_number
end
end
同樣,您可以生成一個 migration 來從命令列中刪除一列:
$ bin/rails generate migration RemovePartNumberFromProducts part_number:string
產生
class RemovePartNumberFromProducts < ActiveRecord::Migration[7.0]
def change
remove_column :products, :part_number, :string
end
end
您不僅限於一個神奇生成的列。例如:
$ bin/rails generate migration AddDetailsToProducts part_number:string price:decimal
產生
class AddDetailsToProducts < ActiveRecord::Migration[7.0]
def change
add_column :products, :part_number, :string
add_column :products, :price, :decimal
end
end
如果 migration 名稱的格式為“CreateXXX”並且是 後跟列名和型別列表,然後是 migration 建立表 將生成帶有列出的列的 XXX。例如:
$ bin/rails generate migration CreateProducts name:string part_number:string
產生
class CreateProducts < ActiveRecord::Migration[7.0]
def change
create_table :products do |t|
t.string :name
t.string :part_number
t.timestamps
end
end
end
與往常一樣,為您生成的內容只是一個起點。你可以加
或透過編輯
db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb
檔案。
此外,生成器接受列型別為 references
(也可作為
belongs_to
)。例如,
$ bin/rails generate migration AddUserRefToProducts user:references
生成以下 add_reference
呼叫:
class AddUserRefToProducts < ActiveRecord::Migration[7.0]
def change
add_reference :products, :user, foreign_key: true
end
end
這個 migration 將建立一個 user_id
列,references 是一個
建立列、索引、外部 keys 甚至多型的簡寫
association 列。
如果 JoinTable
是名稱的一部分,還有一個生成器將生成連線表:
$ bin/rails generate migration CreateJoinTableCustomerProduct customer product
將產生以下 migration:
class CreateJoinTableCustomerProduct < ActiveRecord::Migration[7.0]
def change
create_join_table :customers, :products do |t|
# t.index [:customer_id, :product_id]
# t.index [:product_id, :customer_id]
end
end
end
2.2 Model 發電機
model 和 scaffold 生成器將建立適合新增的 migrations 一個新的 model。此 migration 已包含建立 相關表。如果你告訴 Rails 你想要什麼列,那麼語句 新增這些列也將被建立。例如,執行:
$ bin/rails generate model Product name:string description:text
將建立一個看起來像這樣的 migration
class CreateProducts < ActiveRecord::Migration[7.0]
def change
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
end
您可以根據需要附加任意數量的列名/型別對。
2.3 傳遞修飾符
一些常用的型別修飾符可以直接傳入 命令列。它們用花括號括起來並遵循欄位型別:
例如,執行:
$ bin/rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic}
將產生一個看起來像這樣的 migration
class AddDetailsToProducts < ActiveRecord::Migration[7.0]
def change
add_column :products, :price, :decimal, precision: 5, scale: 2
add_reference :products, :supplier, polymorphic: true
end
end
提示:檢視生成器幫助輸出以獲取更多詳細資訊。
3 寫一個 Migration
使用其中一個生成器建立 migration 後,是時候 開始工作!
3.1 建立表
create_table
方法是最基本的方法之一,但大多數時候,
將使用 model 或 scaffold 生成器為您生成。一個典型的
使用將是
create_table :products do |t|
t.string :name
end
它建立了一個 products
表,其中包含一個名為 name
的列。
預設情況下,create_table
將建立一個名為 id
的主 key。你可以改變
帶有 :primary_key
選項的主 key 的名稱(不要忘記
更新相應的 model),或者,如果您根本不需要主要的 key,您
可以透過選項 id: false
。如果您需要傳遞特定於資料庫的選項
您可以在 :options
選項中放置一個 SQL 片段。例如:
create_table :products, options: "ENGINE=BLACKHOLE" do |t|
t.string :name, null: false
end
將 ENGINE=BLACKHOLE
附加到用於建立表的 SQL 語句。
可以在 create_table
塊內建立的列上建立索引
透過將 true 或選項雜湊傳遞給 :index
選項:
create_table :users do |t|
t.string :name, index: true
t.string :email, index: { unique: true, name: 'unique_emails' }
end
您也可以傳遞帶有表的任何描述的 :comment
選項
將儲存在資料庫本身中,並且可以透過資料庫管理進行 viewed
工具,例如 MySQL Workbench 或 PgAdmin III。強烈建議指定
migrations 中對大型資料庫應用程式的評論,因為它可以幫助人們
瞭解資料 model 並生成文件。
目前只有 MySQL 和 PostgreSQL 介面卡支援註釋。
3.2 建立連線表
migration 方法 create_join_table
建立一個 HABTM(擁有並屬於
許多)連線表。一個典型的用途是:
create_join_table :products, :categories
它建立了一個 categories_products
表,其中有兩列稱為
category_id
和 product_id
。這些列的選項 :null
設定為
預設為 false
。這可以透過指定 :column_options
來覆蓋
選項:
create_join_table :products, :categories, column_options: { null: true }
預設情況下,連線表的名稱來自前兩個的並集
按字母順序提供給 create_join_table 的引數。
要自定義表的名稱,請提供 :table_name
選項:
create_join_table :products, :categories, table_name: :categorization
建立一個 categorization
表。
create_join_table
也接受一個塊,你可以用它來新增索引
(預設情況下不建立)或附加列:
create_join_table :products, :categories do |t|
t.index :product_id
t.index :category_id
end
3.3 換表
create_table
的近親是 change_table
,用於改變現有的
表。它的使用方式與 create_table
類似,但物件
屈服於塊知道更多的技巧。例如:
change_table :products do |t|
t.remove :description, :name
t.string :part_number
t.index :part_number
t.rename :upccode, :upc_code
end
刪除 description
和 name
列,建立一個 part_number
字串
列並在其上新增索引。最後,它重新命名了 upccode
列。
3.4 更改列
像 remove_column
和 add_column
Rails 提供了 change_column
migration 方法。
change_column :products, :part_number, :text
這會將 products 表上的列 part_number
更改為 :text
欄位。
注意 change_column
命令是不可逆的。
除了change_column
,change_column_null
和change_column_default
方法專門用於更改非空約束和預設值
列的 values。
change_column_null :products, :name, false
change_column_default :products, :approved, from: true, to: false
這將產品上的 :name
欄位設定為 NOT NULL
列和預設值
:approved
欄位的 value 從真到假。
你也可以把上面的 change_column_default
migration 寫成
change_column_default :products, :approved, false
,但與之前不同
例如,這將使您的 migration 不可逆。
3.5 列修飾符
建立或更改列時可以應用列修飾符:
-
comment
為列添加註釋。 -
collation
指定string
或text
列的排序規則。 -
default
允許在列上設定預設的 value。請注意,如果您 正在使用動態 value(例如日期),預設只會被計算 第一次(即在應用 migration 的日期)。將nil
用於NULL
。 -
limit
設定string
列的最大字元數 以及text/binary/integer
列的最大位元組數。 -
null
在列中允許或禁止NULL
values。 -
precision
指定decimal/numeric/datetime/time
列的精度。 -
scale
指定decimal
和numeric
列的比例, 表示小數點後的位數。
對於 add_column
或 change_column
,沒有新增索引的選項。
它們需要使用 add_index
單獨新增。
某些介面卡可能支援其他選項;檢視介面卡特定的 API 文件 瞭解更多資訊。
null
和 default
不能透過命令列指定。
3.6 參考資料
add_reference
方法允許建立一個適當命名的列。
add_reference :users, :role
這個 migration 將在使用者表中建立一個 role_id
列。它創造了一個
此列的索引也是如此,除非明確告知不要使用
index: false
選項:
add_reference :users, :role, index: false
方法 add_belongs_to
是 add_reference
的別名。
add_belongs_to :taggings, :taggable, polymorphic: true
多型選項將在標籤表上建立兩列,它們可以
用於多型 associations:taggable_type
和 taggable_id
。
可以使用 foreign_key
選項建立外部 key。
add_reference :users, :role, foreign_key: true
如需更多 add_reference
選項,請訪問 API 文件。
也可以刪除引用:
remove_reference :products, :user, foreign_key: true, index: false
3.7 國外 Keys
雖然不是必需的,但您可能希望將外部 key 約束新增到 保證參照完整性。
add_foreign_key :articles, :authors
這在 articles
的 author_id
列中添加了一個新的外部 key
桌子。 key 引用 authors
表的 id
列。如果
列名不能從表名派生,您可以使用
:column
和 :primary_key
選項。
Rails 會為每個外來的 key 生成一個名字
fk_rails_
後跟 10 個確定性的字元
從 from_table
和 column
生成。
如果需要,可以使用 :name
選項指定不同的名稱。
Active Record 僅支援單列外部 keys。 execute
和
structure.sql
需要使用複合國外 keys。看
模式轉儲和你。
國外的 keys 也可以去掉:
# 讓 Active Record 找出列名
remove_foreign_key :accounts, :branches
# 刪除特定列的外部 key
remove_foreign_key :accounts, column: :owner_id
# 按名稱刪除外部 key
remove_foreign_key :accounts, name: :special_fk_name
3.8 當 Helper 不夠用時
如果 Active Record 提供的 helpers 不夠用,可以使用 execute
執行任意SQL的方法:
Product.connection.execute("UPDATE products SET price = 'free' WHERE 1=1")
有關各個方法的更多詳細資訊和示例,請檢視 API 文件。
特別是文件
ActiveRecord::ConnectionAdapters::SchemaStatements
(它提供了 change
、up
和 down
方法中可用的方法),
ActiveRecord::ConnectionAdapters::TableDefinition
(它提供了 create_table
生成的物件上可用的方法)
和
ActiveRecord::ConnectionAdapters::Table
(它提供了 change_table
生成的物件上可用的方法)。
3.9 使用 change
方法
change
方法是編寫 migrations 的主要方式。它適用於
大多數情況下,Active Record 知道如何反轉 migration
自動地。目前,change
方法只支援這些migration
定義:
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
change_table
也是可逆的,只要block不呼叫change
,
change_default
或 remove
。
如果您提供列型別作為第三個,則 remove_column
是可逆的
爭論。也提供原始列選項,否則 Rails 不能
回滾時完全重新建立列:
remove_column :posts, :slug, :string, null: false, default: ''
如果您需要使用任何其他方法,則應使用 reversible
或者編寫 up
和 down
方法而不是使用 change
方法。
3.10 使用 reversible
複雜的 migrations 可能需要處理 Active Record 不知道如何處理
扭轉。您可以使用 reversible
指定執行
migration 以及恢復它時還需要做什麼。例如:
class ExampleMigration < ActiveRecord::Migration[7.0]
def change
create_table :distributors do |t|
t.string :zipcode
end
reversible do |dir|
dir.up do
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5) NO INHERIT;
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
end
end
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
end
使用 reversible
將確保指令在
順序也對。如果還原前面的示例 migration,
down
塊將在移除 home_page_url
列後執行,並且
就在表 distributors
被刪除之前。
有時您的 migration 會做一些完全不可逆的事情;為了
例如,它可能會破壞一些資料。在這種情況下,您可以提高
ActiveRecord::IrreversibleMigration
在您的 down
塊中。如果有人嘗試
要恢復您的 migration,將顯示一條錯誤訊息,指出它
做不到。
3.11 使用 up
/down
方法
您也可以使用 up
和 down
方法使用舊樣式的 migration
而不是 change
方法。
up
方法應該描述你想對你的
模式,你的 migration 的 down
方法應該恢復
由 up
方法完成的轉換。換句話說,資料庫模式
如果您先執行 up
,然後執行 down
,則應該保持不變。例如,如果你
在 up
方法中建立一個表,您應該在 down
方法中刪除它。它
以完全相反的順序執行轉換是明智的
在 up
方法中製作。 reversible
部分中的示例等效於:
class ExampleMigration < ActiveRecord::Migration[7.0]
def up
create_table :distributors do |t|
t.string :zipcode
end
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5);
SQL
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
def down
rename_column :users, :email_address, :email
remove_column :users, :home_page_url
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
drop_table :distributors
end
end
如果你的 migration 是不可逆的,你應該加註
ActiveRecord::IrreversibleMigration
來自您的 down
方法。如果有人嘗試
要恢復您的 migration,將顯示一條錯誤訊息,指出它
做不到。
3.12 恢復以前的 Migration
您可以使用 Active Record 的 revert
方法回滾 migrations 的能力:
require_relative "20121212123456_example_migration"
class FixupExampleMigration < ActiveRecord::Migration[7.0]
def change
revert ExampleMigration
create_table(:apples) do |t|
t.string :variety
end
end
end
revert
方法也接受要反轉的指令塊。
這對於恢復以前的 migrations 的選定部分可能很有用。
例如,假設 ExampleMigration
已提交併且它
後來決定最好使用 Active Record 驗證,
代替 CHECK
約束,以驗證郵政編碼。
class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration[7.0]
def change
revert do
# copy-pasted code from ExampleMigration
reversible do |dir|
dir.up do
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5);
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
end
end
# The rest of the migration was ok
end
end
end
不使用 revert
也可以編寫相同的 migration
但這將涉及更多步驟:顛倒順序
create_table
和 reversible
的,替換 create_table
由 drop_table
,最後由 down
替換 up
,反之亦然。
這一切都由 revert
處理。
4 執行 Migrations
Rails 提供了一組 rails 命令來執行某些 migrations 組。
您將使用的第一個 migration 相關 rails 命令可能是
bin/rails db:migrate
。在最基本的形式中,它只執行 change
或 up
所有尚未執行的 migrations 的方法。如果有
沒有這樣的migrations,它退出。它將按順序執行這些 migrations
在 migration 日期。
注意,執行 db:migrate
命令也會呼叫 db:schema:dump
命令,它
將更新您的 db/schema.rb
檔案以匹配您的資料庫結構。
如果指定目標版本,Active Record 將執行所需的 migrations (change, up, down) 直到達到指定的版本。版本 是 migration 檔名的數字字首。例如,要遷移 到版本 20080906120000 執行:
$ bin/rails db:migrate VERSION=20080906120000
如果版本 20080906120000 大於當前版本(即
向上遷移),這將執行 change
(或 up
)方法
在所有 migrations 上直到和
包括20080906120000,以後不會再執行migrations。如果
向下遷移,這將在所有 migrations 上執行 down
方法
低至但不包括 20080906120000。
4.1 回滾
一個常見的任務是回滾最後一個 migration。例如,如果你做了一個 錯誤並希望改正。而不是追蹤版本 與之前的 migration 相關聯的編號,您可以執行:
$ bin/rails db:rollback
這將透過恢復 change
來回滾最新的 migration
方法或透過執行 down
方法。如果您需要撤消
幾個migrations你可以提供一個STEP
引數:
$ bin/rails db:rollback STEP=3
將恢復最後 3 migrations。
db:migrate:redo
命令是回滾然後遷移的快捷方式
再次備份。與 db:rollback
命令一樣,您可以使用 STEP
引數
如果您需要返回多個版本,例如:
$ bin/rails db:migrate:redo STEP=3
這些 rails 命令都沒有做任何你用 db:migrate
做不到的事情。他們
是為了方便起見,因為您不需要明確指定
要遷移到的版本。
4.2 設定資料庫
bin/rails db:setup
命令將建立資料庫、載入模式並初始化
它與種子資料。
4.3 重置資料庫
bin/rails db:reset
命令將刪除資料庫並重新設定它。這是
功能上等同於 bin/rails db:drop db:setup
。
這與執行所有 migrations 不同。它只會使用
當前 db/schema.rb
或 db/structure.sql
檔案的內容。如果一個 migration 不能回滾,
bin/rails db:reset
可能幫不了你。要了解有關轉儲架構的更多資訊,請參閱
Schema Dumping and You 部分。
4.4 執行特定的 Migrations
如果您需要向上或向下執行特定的 migration,則 db:migrate:up
和
db:migrate:down
命令會做到這一點。只需指定適當的版本和
相應的 migration 將有其 change
、up
或 down
方法
呼叫,例如:
$ bin/rails db:migrate:up VERSION=20080906120000
將透過執行 change
方法(或
up
方法)。該命令將
首先檢查migration是否已經執行,如果
Active Record 認為它已經運行了。
4.5 在不同環境下執行 Migrations
預設情況下,執行 bin/rails db:migrate
將在 development
環境中執行。
要針對另一個環境執行 migrations,您可以使用
RAILS_ENV
執行命令時的環境變數。例如執行
migrations 針對您可以執行的 test
環境:
$ bin/rails db:migrate RAILS_ENV=test
4.6 改變執行 Migrations 的輸出
預設情況下,migrations 會準確地告訴您他們在做什麼以及花了多長時間。 A migration 建立表並新增索引可能會產生這樣的輸出
== CreateProducts: migrating =================================================
-- create_table(:products)
-> 0.0028s
== CreateProducts: migrated (0.0028s) ========================================
migrations 中提供了幾種方法,允許您控制所有這些:
方法 | 目的 |
---|---|
suppress_messages |
將一個塊作為引數並抑制該塊生成的任何輸出。 |
say |
接受一個訊息引數並按原樣輸出它。可以傳遞第二個布林引數來指定是否縮排。 |
say_with_time |
輸出文字以及執行其塊所需的時間。如果塊返回一個整數,則假定它是受影響的行數。 |
例如,這個 migration:
class CreateProducts < ActiveRecord::Migration[7.0]
def change
suppress_messages do
create_table :products do |t|
t.string :name
t.text :description
t.timestamps
end
end
say "Created a table"
suppress_messages {add_index :products, :name}
say "and an index!", true
say_with_time 'Waiting for a while' do
sleep 10
250
end
end
end
生成以下輸出
== CreateProducts: migrating =================================================
-- Created a table
-> and an index!
-- Waiting for a while
-> 10.0013s
-> 250 rows
== CreateProducts: migrated (10.0054s) =======================================
如果你想讓 Active Record 不輸出任何東西,那麼執行 bin/rails db:migrate
VERBOSE=false
將抑制所有輸出。
5 更改現有的 Migrations
偶爾你會在寫 migration 時出錯。如果你有
已經運行了 migration,那麼你不能只編輯 migration 並執行
migration 再次:Rails 認為它已經運行了 migration,所以會這樣做
執行 bin/rails db:migrate
時什麼也沒有。您必須回滾 migration(對於
以 bin/rails db:rollback
為例),編輯你的 migration,然後執行
bin/rails db:migrate
執行更正後的版本。
一般來說,編輯現有的 migrations 不是一個好主意。你會 為你自己和你的同事創造額外的工作,並導致嚴重的頭痛 如果現有版本的 migration 已經在生產環境中執行 機器。相反,您應該編寫一個新的 migration 來執行更改 你需要。編輯一個新生成的 migration 還沒有 致力於原始碼控制(或更一般地說,尚未傳播 超出您的開發機器)相對無害。
revert
方法在編寫新的 migration 以撤消時很有用
以前的 migrations 全部或部分
(參見上面的 Reverting Previous Migrations)。
6 模式傾銷和你
6.1 架構檔案有什麼用?
Migrations,儘管它們可能很強大,但並不是您的權威來源
資料庫架構。您的資料庫仍然是權威來源。預設情況下,
Rails 生成 db/schema.rb
試圖捕獲當前狀態
您的資料庫架構。
建立您的新實例往往會更快並且更不容易出錯
透過 bin/rails db:schema:load
載入模式檔案來載入應用程式的資料庫
而不是重放整個 migration 歷史。
舊 migrations 可能無法正確應用,如果
migrations 使用不斷變化的外部依賴項或依賴應用程式程式碼
與您的 migrations 分開進化。
如果您想快速檢視什麼屬性,架構檔案也很有用 Active Record 物件有。此資訊不在 model 的程式碼中,而是在 經常分佈在幾個migrations,但資訊很好 總結在模式檔案中。
6.2 模式轉儲的型別
Rails 生成的模式轉儲的格式由
config/application.rb
中的 config.active_record.schema_format
設定。經過
預設格式為 :ruby
,但也可以設定為 :sql
。
如果選擇 :ruby
,則架構儲存在 db/schema.rb
中。如果你看
在這個檔案中,你會發現它看起來非常像一個非常大的 migration:
ActiveRecord::Schema.define(version: 2008_09_06_171750) do
create_table "authors", force: true do |t|
t.string "name"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "products", force: true do |t|
t.string "name"
t.text "description"
t.datetime "created_at"
t.datetime "updated_at"
t.string "part_number"
end
end
在許多方面,這正是事實。該檔案是透過檢查
資料庫並使用create_table
、add_index
等表示其結構
在。
db/schema.rb
無法表達您的資料庫可能支援的所有內容,例如
觸發器、序列、儲存過程等。 而 migrations
可以使用 execute
建立不受支援的資料庫結構
Ruby migration DSL,這些構造可能無法由
模式轉儲器。如果您正在使用這些功能,您應該設定架構
格式為 :sql
以獲得準確的模式檔案
建立新的資料庫實例。
當schema格式設定為:sql
時,會dump資料庫結構
使用特定於資料庫的工具進入 db/structure.sql
。例如,對於
PostgreSQL,使用了 pg_dump
實用程式。對於 MySQL 和 MariaDB,此檔案將
包含各種表的 SHOW CREATE TABLE
的輸出。
要從 db/structure.sql
載入架構,請執行 bin/rails db:schema:load
。
載入這個檔案是透過執行它包含的 SQL 語句來完成的。經過
定義,這將建立資料庫結構的完美副本。
6.3 模式轉儲和原始碼控制
因為模式檔案通常用於建立新的資料庫,所以它強烈 建議您將架構檔案簽入原始碼管理。
當兩個分支修改架構時,架構檔案中可能會發生合併衝突。
要解決這些衝突,請執行 bin/rails db:migrate
以重新生成架構檔案。
7 Active Record 和參照完整性
Active Record 方式聲稱智慧屬於你的 models,而不是在 資料庫。因此,觸發器或約束等功能, 將一些情報推回到資料庫中,並不是很嚴重 用過的。
諸如 validates :foreign_key, uniqueness: true
之類的驗證是一種方式
其中 models 可以強制執行資料完整性。 :dependent
選項在
associations 允許 models 自動銷燬子物件時
父級被銷燬。就像在應用程式級別執行的任何東西一樣,
這些不能保證參照完整性,所以有些人會增加它們
資料庫中有外來鍵約束。
雖然 Active Record 沒有提供直接使用的所有工具
這樣的特性,可以使用execute
方法來執行任意SQL。
8 Migrations 和種子資料
Rails 的 migration 特性的主要目的是發出修改 模式使用一致的過程。 Migrations 也可以使用 新增或修改資料。這在無法銷燬的現有資料庫中很有用 並重新建立,例如生產資料庫。
class AddInitialProducts < ActiveRecord::Migration[7.0]
def up
5.times do |i|
Product.create(name: "Product ##{i}", description: "A product.")
end
end
def down
Product.delete_all
end
end
為了在建立資料庫後新增初始資料,Rails 有一個內建的
“種子”功能可加快程序。這是特別
在開發和測試環境中頻繁重新載入資料庫時很有用。
要開始使用此功能,請填寫 db/seeds.rb
一些
Ruby 程式碼,並執行 bin/rails db:seed
:
5.times do |i|
Product.create(name: "Product ##{i}", description: "A product.")
end
這通常是設定空白資料庫的更簡潔的方法 應用。
9 舊的 Migrations
db/schema.rb
或 db/structure.sql
是您當前狀態的快照
資料庫,並且是重建該資料庫的權威來源。這
可以刪除舊的 migration 檔案。
當您刪除 db/migrate/
目錄中的 migration 檔案時,任何環境
當這些檔案仍然存在時執行 bin/rails db:migrate
的位置將包含一個引用
到特定於它們在內部 Rails 資料庫中的 migration 時間戳
名為 schema_migrations
的表。此表用於跟蹤是否
migrations 已在特定環境中執行。
如果您執行 bin/rails db:migrate:status
命令,它會顯示狀態
(向上或向下)每個 migration,你應該看到 ********** NO FILE **********
顯示在任何已刪除的 migration 檔案旁邊,該檔案曾經在
特定環境,但在 db/migrate/
目錄中已找不到。
不過,有一個警告。從引擎安裝遷移的 Rake 任務是冪等的。由於先前安裝而存在於父應用程式中的 Migration 將被跳過,並使用新的前導時間戳複製丟失的那些。如果您刪除舊引擎遷移並再次執行安裝任務,您將獲得帶有新時間戳的新檔案,並且 db:migrate
將嘗試再次執行它們。
因此,您通常希望保留來自引擎的 migrations。他們有這樣的特殊評論:
# 這個migration來自blorgh(原為20210621082949)
回饋
我們鼓勵您幫助提高本指南的品質。
如果您發現任何拼寫錯誤或資訊錯誤,請提供回饋。 要開始回饋,您可以閱讀我們的 回饋 部分。
您還可能會發現不完整的內容或不是最新的內容。 請務必為 main 新增任何遺漏的文件。假設是 非穩定版指南(edge guides) 請先驗證問題是否已經在主分支上解決。 請前往 Ruby on Rails 指南寫作準則 查看寫作風格和慣例。
如果由於某種原因您發現要修復的內容但無法自行修補,請您 提出 issue。
關於 Ruby on Rails 的任何類型的討論歡迎提供任何文件至 rubyonrails-docs 討論區。