<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                # Active Record 數據庫遷移 遷移是 Active Record 提供的一個功能,按照時間順序管理數據庫模式。使用遷移,無需編寫 SQL,使用簡單的 Ruby DSL 就能修改數據表。 讀完本文,你將學到: * 生成遷移文件的生成器; * Active Record 提供用來修改數據庫的方法; * 管理遷移和數據庫模式的 Rake 任務; * 遷移和 `schema.rb` 文件的關系; ### Chapters 1. [遷移簡介](#%E8%BF%81%E7%A7%BB%E7%AE%80%E4%BB%8B) 2. [創建遷移](#%E5%88%9B%E5%BB%BA%E8%BF%81%E7%A7%BB) * [單獨創建遷移](#%E5%8D%95%E7%8B%AC%E5%88%9B%E5%BB%BA%E8%BF%81%E7%A7%BB) * [模型生成器](#%E6%A8%A1%E5%9E%8B%E7%94%9F%E6%88%90%E5%99%A8) * [支持的類型修飾符](#%E6%94%AF%E6%8C%81%E7%9A%84%E7%B1%BB%E5%9E%8B%E4%BF%AE%E9%A5%B0%E7%AC%A6) 3. [編寫遷移](#%E7%BC%96%E5%86%99%E8%BF%81%E7%A7%BB) * [創建數據表](#%E5%88%9B%E5%BB%BA%E6%95%B0%E6%8D%AE%E8%A1%A8) * [創建聯合數據表](#%E5%88%9B%E5%BB%BA%E8%81%94%E5%90%88%E6%95%B0%E6%8D%AE%E8%A1%A8) * [修改數據表](#%E4%BF%AE%E6%94%B9%E6%95%B0%E6%8D%AE%E8%A1%A8) * [如果幫助方法不夠用](#%E5%A6%82%E6%9E%9C%E5%B8%AE%E5%8A%A9%E6%96%B9%E6%B3%95%E4%B8%8D%E5%A4%9F%E7%94%A8) * [使用 `change` 方法](#%E4%BD%BF%E7%94%A8-change-%E6%96%B9%E6%B3%95) * [使用 `reversible` 方法](#%E4%BD%BF%E7%94%A8-reversible-%E6%96%B9%E6%B3%95) * [使用 `up` 和 `down` 方法](#%E4%BD%BF%E7%94%A8-up-%E5%92%8C-down-%E6%96%B9%E6%B3%95) * [撤銷之前的遷移](#%E6%92%A4%E9%94%80%E4%B9%8B%E5%89%8D%E7%9A%84%E8%BF%81%E7%A7%BB) 4. [運行遷移](#%E8%BF%90%E8%A1%8C%E8%BF%81%E7%A7%BB) * [回滾](#%E5%9B%9E%E6%BB%9A) * [搭建數據庫](#%E6%90%AD%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%BA%93) * [重建數據庫](#%E9%87%8D%E5%BB%BA%E6%95%B0%E6%8D%AE%E5%BA%93) * [運行指定的遷移](#%E8%BF%90%E8%A1%8C%E6%8C%87%E5%AE%9A%E7%9A%84%E8%BF%81%E7%A7%BB) * [在不同的環境中運行遷移](#%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E7%8E%AF%E5%A2%83%E4%B8%AD%E8%BF%90%E8%A1%8C%E8%BF%81%E7%A7%BB) * [修改運行遷移時的輸出](#%E4%BF%AE%E6%94%B9%E8%BF%90%E8%A1%8C%E8%BF%81%E7%A7%BB%E6%97%B6%E7%9A%84%E8%BE%93%E5%87%BA) 5. [修改現有的遷移](#%E4%BF%AE%E6%94%B9%E7%8E%B0%E6%9C%89%E7%9A%84%E8%BF%81%E7%A7%BB) 6. [導出模式](#%E5%AF%BC%E5%87%BA%E6%A8%A1%E5%BC%8F) * [模式文件的作用](#%E6%A8%A1%E5%BC%8F%E6%96%87%E4%BB%B6%E7%9A%84%E4%BD%9C%E7%94%A8) * [導出的模式文件類型](#%E5%AF%BC%E5%87%BA%E7%9A%84%E6%A8%A1%E5%BC%8F%E6%96%87%E4%BB%B6%E7%B1%BB%E5%9E%8B) * [模式導出和版本控制](#%E6%A8%A1%E5%BC%8F%E5%AF%BC%E5%87%BA%E5%92%8C%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6) 7. [Active Record 和引用完整性](#active-record-%E5%92%8C%E5%BC%95%E7%94%A8%E5%AE%8C%E6%95%B4%E6%80%A7) 8. [遷移和種子數據](#%E8%BF%81%E7%A7%BB%E5%92%8C%E7%A7%8D%E5%AD%90%E6%95%B0%E6%8D%AE) ### 1 遷移簡介 遷移使用一種統一、簡單的方式,按照時間順序修改數據庫的模式。遷移使用 Ruby DSL 編寫,因此不用手動編寫 SQL 語句,對數據庫的操作和所用的數據庫種類無關。 你可以把每個遷移看做數據庫的一個修訂版本。數據庫中一開始什么也沒有,各個遷移會添加或刪除數據表、字段或記錄。Active Record 知道如何按照時間線更新數據庫,不管數據庫現在的模式如何,都能更新到最新結構。同時,Active Record 還會更新 `db/schema.rb` 文件,匹配最新的數據庫結構。 下面是一個遷移示例: ``` class CreateProducts < ActiveRecord::Migration def change create_table :products do |t| t.string :name t.text :description t.timestamps end end end ``` 這個遷移創建了一個名為 `products` 的表,然后在表中創建字符串字段 `name` 和文本字段 `description`。名為 `id` 的主鍵字段會被自動創建。`id` 字段是所有 Active Record 模型的默認主鍵。`timestamps` 方法創建兩個字段:`created_at` 和 `updated_at`。如果數據表中有這兩個字段,Active Record 會負責操作。 注意,對數據庫的改動按照時間向前 推移。運行遷移之前,數據表還不存在。運行遷移后,才會創建數據表。Active Record 知道如何撤銷遷移,如果回滾這次遷移,數據表會被刪除。 在支持事務的數據庫中,對模式的改動會在一個事務中執行。如果數據庫不支持事務,遷移失敗時,成功執行的操作將無法回滾。如要回滾,必須手動改回來。 某些查詢無法在事務中運行。如果適配器支持 DDL 事務,可以在某個遷移中調用 `disable_ddl_transaction!` 方法禁用。 如果想在遷移中執行 Active Record 不知如何撤銷的操作,可以使用 `reversible` 方法: ``` class ChangeProductsPrice < ActiveRecord::Migration 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 ``` 或者不用 `change` 方法,分別使用 `up` 和 `down` 方法: ``` class ChangeProductsPrice < ActiveRecord::Migration 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 創建遷移 #### 2.1 單獨創建遷移 遷移文件存儲在 `db/migrate` 文件夾中,每個遷移保存在一個文件中。文件名采用 `YYYYMMDDHHMMSS_create_products.rb` 形式,即一個 UTC 時間戳后加以下劃線分隔的遷移名。遷移的類名(駝峰式)要和文件名時間戳后面的部分匹配。例如,在 `20080906120000_create_products.rb` 文件中要定義 `CreateProducts` 類;在 `20080906120001_add_details_to_products.rb` 文件中要定義 `AddDetailsToProducts` 類。文件名中的時間戳決定要運行哪個遷移,以及按照什么順序運行。從其他程序中復制遷移,或者自己生成遷移時,要注意運行的順序。 自己計算時間戳不是件簡單的事,所以 Active Record 提供了一個生成器: ``` $ rails generate migration AddPartNumberToProducts ``` 這個命令生成一個空的遷移,但名字已經起好了: ``` class AddPartNumberToProducts < ActiveRecord::Migration def change end end ``` 如果遷移的名字是“AddXXXToYYY”或者“RemoveXXXFromYYY”這種格式,而且后面跟著一個字段名和類型列表,那么遷移中會生成合適的 `add_column` 或 `remove_column` 語句。 ``` $ rails generate migration AddPartNumberToProducts part_number:string ``` 這個命令生成的遷移如下: ``` class AddPartNumberToProducts < ActiveRecord::Migration def change add_column :products, :part_number, :string end end ``` 如果想為新建的字段創建添加索引,可以這么做: ``` $ rails generate migration AddPartNumberToProducts part_number:string:index ``` 這個命令生成的遷移如下: ``` class AddPartNumberToProducts < ActiveRecord::Migration def change add_column :products, :part_number, :string add_index :products, :part_number end end ``` 類似地,還可以生成刪除字段的遷移: ``` $ rails generate migration RemovePartNumberFromProducts part_number:string ``` 這個命令生成的遷移如下: ``` class RemovePartNumberFromProducts < ActiveRecord::Migration def change remove_column :products, :part_number, :string end end ``` 遷移生成器不單只能創建一個字段,例如: ``` $ rails generate migration AddDetailsToProducts part_number:string price:decimal ``` 生成的遷移如下: ``` class AddDetailsToProducts < ActiveRecord::Migration def change add_column :products, :part_number, :string add_column :products, :price, :decimal end end ``` 如果遷移名是“CreateXXX”形式,后面跟著一串字段名和類型聲明,遷移就會創建名為“XXX”的表,以及相應的字段。例如: ``` $ rails generate migration CreateProducts name:string part_number:string ``` 生成的遷移如下: ``` class CreateProducts < ActiveRecord::Migration def change create_table :products do |t| t.string :name t.string :part_number end end end ``` 生成器生成的只是一些基礎代碼,你可以根據需要修改 `db/migrate/YYYYMMDDHHMMSS_add_details_to_products.rb` 文件,增刪代碼。 在生成器中還可把字段類型設為 `references`(還可使用 `belongs_to`)。例如: ``` $ rails generate migration AddUserRefToProducts user:references ``` 生成的遷移如下: ``` class AddUserRefToProducts < ActiveRecord::Migration def change add_reference :products, :user, index: true end end ``` 這個遷移會創建 `user_id` 字段,并建立索引。 如果遷移名中包含 `JoinTable`,生成器還會創建聯合數據表: ``` rails g migration CreateJoinTableCustomerProduct customer product ``` 生成的遷移如下: ``` class CreateJoinTableCustomerProduct < ActiveRecord::Migration 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 模型生成器 模型生成器和腳手架生成器會生成合適的遷移,創建模型。遷移中會包含創建所需數據表的代碼。如果在生成器中指定了字段,還會生成創建字段的代碼。例如,運行下面的命令: ``` $ rails generate model Product name:string description:text ``` 會生成如下的遷移: ``` class CreateProducts < ActiveRecord::Migration def change create_table :products do |t| t.string :name t.text :description t.timestamps end end end ``` 字段的名字和類型數量不限。 #### 2.3 支持的類型修飾符 在字段類型后面,可以在花括號中添加選項。可用的修飾符如下: * `limit`:設置 `string/text/binary/integer` 類型字段的最大值; * `precision`:設置 `decimal` 類型字段的精度,即數字的位數; * `scale`:設置 `decimal` 類型字段小數點后的數字位數; * `polymorphic`:為 `belongs_to` 關聯添加 `type` 字段; * `null`:是否允許該字段的值為 `NULL`; 例如,執行下面的命令: ``` $ rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic} ``` 生成的遷移如下: ``` class AddDetailsToProducts < ActiveRecord::Migration def change add_column :products, :price, :decimal, precision: 5, scale: 2 add_reference :products, :supplier, polymorphic: true, index: true end end ``` ### 3 編寫遷移 使用前面介紹的生成器生成遷移后,就可以開始寫代碼了。 #### 3.1 創建數據表 `create_table` 方法最常用,大多數時候都會由模型或腳手架生成器生成。典型的用例如下: ``` create_table :products do |t| t.string :name end ``` 這個遷移會創建 `products` 數據表,在數據表中創建 `name` 字段(后面會介紹,還會自動創建 `id` 字段)。 默認情況下,`create_table` 方法會創建名為 `id` 的主鍵。通過 `:primary_key` 選項可以修改主鍵名(修改后別忘了修改相應的模型)。如果不想生成主鍵,可以傳入 `id: false` 選項。如果設置數據庫的選項,可以在 `:options` 選擇中使用 SQL。例如: ``` create_table :products, options: "ENGINE=BLACKHOLE" do |t| t.string :name, null: false end ``` 這樣設置之后,會在創建數據表的 SQL 語句后面加上 `ENGINE=BLACKHOLE`。(MySQL 默認的選項是 `ENGINE=InnoDB`) #### 3.2 創建聯合數據表 `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} ``` 這段代碼會把 `product_id` 和 `category_id` 字段的 `:null` 選項設為 `true`。 如果想修改數據表的名字,可以傳入 `: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 如果幫助方法不夠用 如果 Active Record 提供的幫助方法不夠用,可以使用 `execute` 方法,執行任意的 SQL 語句: ``` Product.connection.execute('UPDATE `products` SET `price`=`free` WHERE 1') ``` 各方法的詳細用法請查閱 API 文檔: * [`ActiveRecord::ConnectionAdapters::SchemaStatements`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html):包含可在 `change`,`up` 和 `down` 中使用的方法; * [`ActiveRecord::ConnectionAdapters::TableDefinition`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html):包含可在 `create_table` 方法的塊參數上調用的方法; * [`ActiveRecord::ConnectionAdapters::Table`](http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html):包含可在 `change_table` 方法的塊參數上調用的方法; #### 3.5 使用 `change` 方法 `change` 是遷移中最常用的方法,大多數情況下都能完成指定的操作,而且 Active Record 知道如何撤這些操作。目前,在 `change` 方法中只能使用下面的方法: * `add_column` * `add_index` * `add_reference` * `add_timestamps` * `create_table` * `create_join_table` * `drop_table`(必須提供代碼塊) * `drop_join_table`(必須提供代碼塊) * `remove_timestamps` * `rename_column` * `rename_index` * `remove_reference` * `rename_table` 只要在塊中不使用 `change`、`change_default` 或 `remove` 方法,`change_table` 中的操作也是可逆的。 如果要使用任何其他方法,可以使用 `reversible` 方法,或者不定義 `change` 方法,而分別定義 `up` 和 `down` 方法。 #### 3.6 使用 `reversible` 方法 Active Record 可能不知如何撤銷復雜的遷移操作,這時可以使用 `reversible` 方法指定運行遷移和撤銷遷移時怎么操作。例如: ``` class ExampleMigration < ActiveRecord::Migration def change create_table :products do |t| t.references :category end reversible do |dir| dir.up do #add a foreign key execute <<-SQL ALTER TABLE products ADD CONSTRAINT fk_products_categories FOREIGN KEY (category_id) REFERENCES categories(id) SQL end dir.down do execute <<-SQL ALTER TABLE products DROP FOREIGN KEY fk_products_categories SQL end end add_column :users, :home_page_url, :string rename_column :users, :email, :email_address end ``` 使用 `reversible` 方法還能確保操作按順序執行。在上面的例子中,如果撤銷遷移,`down` 代碼塊會在 `home_page_url` 字段刪除后、`products` 數據表刪除前運行。 有時,遷移的操作根本無法撤銷,例如刪除數據。這是,可以在 `down` 代碼塊中拋出 `ActiveRecord::IrreversibleMigration` 異常。如果有人嘗試撤銷遷移,會看到一個錯誤消息,告訴他無法撤銷。 #### 3.7 使用 `up` 和 `down` 方法 在遷移中可以不用 `change` 方法,而用 `up` 和 `down` 方法。`up` 方法定義要對數據庫模式做哪些操作,`down` 方法用來撤銷這些操作。也就是說,如果執行 `up` 后立即執行 `down`,數據庫的模式應該沒有任何變化。例如,在 `up` 中創建了數據表,在 `down` 方法中就要將其刪除。撤銷時最好按照添加的相反順序進行。前一節中的 `reversible` 用法示例代碼可以改成: ``` class ExampleMigration < ActiveRecord::Migration def up create_table :products do |t| t.references :category end # add a foreign key execute <<-SQL ALTER TABLE products ADD CONSTRAINT fk_products_categories FOREIGN KEY (category_id) REFERENCES categories(id) 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 products DROP FOREIGN KEY fk_products_categories SQL drop_table :products end end ``` 如果遷移不可撤銷,應該在 `down` 方法中拋出 `ActiveRecord::IrreversibleMigration` 異常。如果有人嘗試撤銷遷移,會看到一個錯誤消息,告訴他無法撤銷。 #### 3.8 撤銷之前的遷移 Active Record 提供了撤銷遷移的功能,通過 `revert` 方法實現: ``` require_relative '2012121212_example_migration' class FixupExampleMigration < ActiveRecord::Migration def change revert ExampleMigration create_table(:apples) do |t| t.string :variety end end end ``` `revert` 方法還可接受一個塊,定義撤銷操作。`revert` 方法可用來撤銷以前遷移的部分操作。例如,`ExampleMigration` 已經執行,但后來覺得最好還是序列化產品列表。那么,可以編寫下面的代碼: ``` class SerializeProductListMigration < ActiveRecord::Migration def change add_column :categories, :product_list reversible do |dir| dir.up do # transfer data from Products to Category#product_list end dir.down do # create Products from Category#product_list end end revert do # copy-pasted code from ExampleMigration create_table :products do |t| t.references :category end reversible do |dir| dir.up do #add a foreign key execute <<-SQL ALTER TABLE products ADD CONSTRAINT fk_products_categories FOREIGN KEY (category_id) REFERENCES categories(id) SQL end dir.down do execute <<-SQL ALTER TABLE products DROP FOREIGN KEY fk_products_categories SQL end end # The rest of the migration was ok end end end ``` 上面這個遷移也可以不用 `revert` 方法,不過步驟就多了:調換 `create_table` 和 `reversible` 的順序,把 `create_table` 換成 `drop_table`,還要對調 `up` 和 `down` 中的代碼。這些操作都可交給 `revert` 方法完成。 ### 4 運行遷移 Rails 提供了很多 Rake 任務,用來執行指定的遷移。 其中最常使用的是 `rake db:migrate`,執行還沒執行的遷移中的 `change` 或 `up` 方法。如果沒有未運行的遷移,直接退出。`rake db:migrate` 按照遷移文件名中時間戳順序執行遷移。 注意,執行 `db:migrate` 時還會執行 `db:schema:dump`,更新 `db/schema.rb` 文件,匹配數據庫的結構。 如果指定了版本,Active Record 會運行該版本之前的所有遷移。版本就是遷移文件名前的數字部分。例如,要運行 20080906120000 這個遷移,可以執行下面的命令: ``` $ rake db:migrate VERSION=20080906120000 ``` 如果 20080906120000 比當前的版本高,上面的命令就會執行所有 20080906120000 之前(包括 20080906120000)的遷移中的 `change` 或 `up` 方法,但不會運行 20080906120000 之后的遷移。如果回滾遷移,則會執行 20080906120000 之前(不包括 20080906120000)的遷移中的 `down` 方法。 #### 4.1 回滾 還有一個常用的操作時回滾到之前的遷移。例如,遷移代碼寫錯了,想糾正。我們無須查找遷移的版本號,直接執行下面的命令即可: ``` $ rake db:rollback ``` 這個命令會回滾上一次遷移,撤銷 `change` 方法中的操作,或者執行 `down` 方法。如果想撤銷多個遷移,可以使用 `STEP` 參數: ``` $ rake db:rollback STEP=3 ``` 這個命令會撤銷前三次遷移。 `db:migrate:redo` 命令可以回滾上一次遷移,然后再次執行遷移。和 `db:rollback` 一樣,如果想重做多次遷移,可以使用 `STEP` 參數。例如: ``` $ rake db:migrate:redo STEP=3 ``` 這些 Rake 任務的作用和 `db:migrate` 一樣,只是用起來更方便,因為無需查找特定的遷移版本號。 #### 4.2 搭建數據庫 `rake db:setup` 任務會創建數據庫,加載模式,并填充種子數據。 #### 4.3 重建數據庫 `rake db:reset` 任務會刪除數據庫,然后重建,等價于 `rake db:drop db:setup`。 這個任務和執行所有遷移的作用不同。`rake db:reset` 使用的是 `schema.rb` 文件中的內容。如果遷移無法回滾,`rake db:reset` 起不了作用。詳細介紹參見“[導出模式](#schema-dumping-and-you)”一節。 #### 4.4 運行指定的遷移 如果想執行指定遷移,或者撤銷指定遷移,可以使用 `db:migrate:up` 和 `db:migrate:down` 任務,指定相應的版本號,就會根據需求調用 `change`、`up` 或 `down` 方法。例如: ``` $ rake db:migrate:up VERSION=20080906120000 ``` 這個命令會執行 20080906120000 遷移中的 `change` 方法或 `up` 方法。`db:migrate:up` 首先會檢測指定的遷移是否已經運行,如果 Active Record 任務已經執行,就不會做任何操作。 #### 4.5 在不同的環境中運行遷移 默認情況下,`rake db:migrate` 任務在 `development` 環境中執行。要在其他環境中運行遷移,執行命令時可以使用環境變量 `RAILS_ENV` 指定環境。例如,要在 `test` 環境中運行遷移,可以執行下面的命令: ``` $ rake db:migrate RAILS_ENV=test ``` #### 4.6 修改運行遷移時的輸出 默認情況下,運行遷移時,會輸出操作了哪些操作,以及花了多長時間。創建數據表并添加索引的遷移產生的輸出如下: ``` == CreateProducts: migrating ================================================= -- create_table(:products) -> 0.0028s == CreateProducts: migrated (0.0028s) ======================================== ``` 在遷移中可以使用很多方法,控制輸出: | 方法 | 作用 | | --- | --- | | suppress_messages | 接受一個代碼塊,禁止代碼塊中所有操作的輸出 | | say | 接受一個消息字符串作為參數,將其輸出。第二個參數是布爾值,指定輸出結果是否縮進 | | say_with_time | 輸出文本,以及執行代碼塊中操作所用時間。如果代碼塊的返回結果是整數,會當做操作的記錄數量 | 例如,下面這個遷移: ``` class CreateProducts < ActiveRecord::Migration 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 輸出任何結果,可以使用 `rake db:migrate VERBOSE=false`。 ### 5 修改現有的遷移 有時編寫的遷移中可能有錯誤,如果已經運行了遷移,不能直接編輯遷移文件再運行遷移。Rails 認為這個遷移已經運行,所以執行 `rake db:migrate` 任務時什么也不會做。這種情況必須先回滾遷移(例如,執行 `rake db:rollback` 任務),編輯遷移文件后再執行 `rake db:migrate` 任務執行改正后的版本。 一般來說,直接修改現有的遷移不是個好主意。這么做會為你以及你的同事帶來額外的工作量,如果這個遷移已經在生產服務器上運行過,還可能帶來不必要的麻煩。你應該編寫一個新的遷移,做所需的改動。編輯新生成還未納入版本控制的遷移(或者更寬泛地說,還沒有出現在開發設備之外),相對來說是安全的。 在新遷移中撤銷之前遷移中的全部操作或者部分操作可以使用 `revert` 方法。(參見前面的 [撤銷之前的遷移](#reverting-previous-migrations) 一節) ### 6 導出模式 #### 6.1 模式文件的作用 遷移的作用并不是為數據庫模式提供可信的參考源。`db/schema.rb` 或由 Active Record 生成的 SQL 文件才有這個作用。`db/schema.rb` 這些文件不可修改,其目的是表示數據庫的當前結構。 部署新程序時,無需運行全部的遷移。直接加載數據庫結構要簡單快速得多。 例如,測試數據庫是這樣創建的:導出開發數據庫的結構(存入文件 `db/schema.rb` 或 `db/structure.sql`),然后導入測試數據庫。 模式文件還可以用來快速查看 Active Record 中有哪些屬性。模型中沒有屬性信息,而且遷移會頻繁修改屬性,但是模式文件中有最終的結果。[annotate_models](https://github.com/ctran/annotate_models) gem 會在模型文件的頂部加入注釋,自動添加并更新模型的模式。 #### 6.2 導出的模式文件類型 導出模式有兩種方法,由 `config/application.rb` 文件中的 `config.active_record.schema_format` 選項設置,可以是 `:sql` 或 `:ruby`。 如果設為 `:ruby`,導出的模式保存在 `db/schema.rb` 文件中。打開這個文件,你會發現內容很多,就像一個很大的遷移: ``` ActiveRecord::Schema.define(version: 20080906171750) 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` 等方法審查數據庫的結構。這個文件盒使用的數據庫類型無關,可以導入任何一種 Active Record 支持的數據庫。如果開發的程序需要兼容多種數據庫,可以使用這個文件。 不過 `db/schema.rb` 也有缺點:無法執行數據庫的某些操作,例如外鍵約束,觸發器,存儲過程。在遷移文件中可以執行 SQL 語句,但導出模式的程序無法從數據庫中重建這些語句。如果你的程序用到了前面提到的數據庫操作,可以把模式文件的格式設為 `:sql`。 `:sql` 格式的文件不使用 Active Record 的模式導出程序,而使用數據庫自帶的導出工具(執行 `db:structure:dump` 任務),把數據庫模式導入 `db/structure.sql` 文件。例如,PostgreSQL 使用 `pg_dump` 導出模式。如果使用 MySQL,`db/structure.sql` 文件中會出現多個 `SHOW CREATE TABLE` 用來創建數據表的語句。 加載模式時,只要執行其中的 SQL 語句即可。按預期,導入后會創建一個完整的數據庫結構。使用 `:sql` 格式,就不能把模式導入其他類型的數據庫中了。 #### 6.3 模式導出和版本控制 因為導出的模式文件是數據庫模式的可信源,強烈推薦將其納入版本控制。 ### 7 Active Record 和引用完整性 Active Record 在模型中,而不是數據庫中設置關聯。因此,需要在數據庫中實現的功能,例如觸發器、外鍵約束,不太常用。 `validates :foreign_key, uniqueness: true` 這個驗證是模型保證數據完整性的一種方法。在關聯中設置 `:dependent` 選項,可以保證父對象刪除后,子對象也會被刪除。和任何一種程序層的操作一樣,這些無法完全保證引用完整性,所以很多人還是會在數據庫中使用外鍵約束。 Active Record 并沒有為使用這些功能提供任何工具,不過 `execute` 方法可以執行任意的 SQL 語句。還可以使用 [foreigner](https://github.com/matthuhiggins/foreigner) 等 gem,為 Active Record 添加外鍵支持(還能把外鍵導出到 `db/schema.rb` 文件)。 ### 8 遷移和種子數據 有些人使用遷移把數據存入數據庫: ``` class AddInitialProducts < ActiveRecord::Migration 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 代碼,然后執行 `rake db:seed` 命令即可: ``` 5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") end ``` 填充新建程序的數據庫,使用這種方法操作起來簡潔得多。 ### 反饋 歡迎幫忙改善指南質量。 如發現任何錯誤,歡迎修正。開始貢獻前,可先行閱讀[貢獻指南:文檔](http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation)。 翻譯如有錯誤,深感抱歉,歡迎 [Fork](https://github.com/ruby-china/guides/fork) 修正,或至此處[回報](https://github.com/ruby-china/guides/issues/new)。 文章可能有未完成或過時的內容。請先檢查 [Edge Guides](http://edgeguides.rubyonrails.org) 來確定問題在 master 是否已經修掉了。再上 master 補上缺少的文件。內容參考 [Ruby on Rails 指南準則](ruby_on_rails_guides_guidelines.html)來了解行文風格。 最后,任何關于 Ruby on Rails 文檔的討論,歡迎到 [rubyonrails-docs 郵件群組](http://groups.google.com/group/rubyonrails-docs)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看