Active Record 資料庫遷移
資料庫遷移可以管理多個實體資料庫所使用的結構描述演進。它解決了常見問題:在本地資料庫中添加欄位以使新功能生效,但不確定如何將此更改推送給其他開發人員和生產伺服器。透過資料庫遷移,您可以將轉換描述在獨立的類別中,這些類別可以簽入版本控制系統並針對可能落後一個、兩個或五個版本的另一個資料庫執行。
簡單遷移的範例
class AddSsl < ActiveRecord::Migration[8.0]
def up
add_column :accounts, :ssl_enabled, :boolean, default: true
end
def down
remove_column :accounts, :ssl_enabled
end
end
此遷移將向 accounts 表格添加一個布林值旗標,如果您要撤銷遷移,則將其移除。它顯示了所有遷移都有兩個方法 up
和 down
,用於描述實施或移除遷移所需的轉換。這些方法可以包含遷移特定的方法,例如 add_column
和 remove_column
,但也可能包含用於生成轉換所需資料的常規 Ruby 程式碼。
需要初始化資料的更複雜遷移的範例
class AddSystemSettings < ActiveRecord::Migration[8.0]
def up
create_table :system_settings do |t|
t.string :name
t.string :label
t.text :value
t.string :type
t.integer :position
end
SystemSetting.create name: 'notice',
label: 'Use notice?',
value: 1
end
def down
drop_table :system_settings
end
end
此遷移首先添加 system_settings
表格,然後使用依賴於該表格的 Active Record 模型在其中建立第一行。它還使用了更進階的 create_table
語法,您可以在一個區塊呼叫中指定完整的表格結構描述。
可用的轉換
建立
-
create_join_table(table_1, table_2, options)
:建立一個連接表格,其名稱為前兩個參數的字典順序。詳情請參閱ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table
。 -
create_table(name, options)
:建立一個名為name
的表格,並將表格物件提供給一個區塊,該區塊可以向其中添加欄位,遵循與add_column
相同的格式。請參閱上面的範例。 options 散列用於附加到建立表格定義的片段,例如「DEFAULT CHARSET=UTF-8」。 -
add_column(table_name, column_name, type, options)
:向名為table_name
的表格添加一個名為column_name
的新欄位,其類型指定為以下類型之一::string
、:text
、:integer
、:float
、:decimal
、:datetime
、:timestamp
、:time
、:date
、:binary
、:boolean
。可以透過傳遞options
散列(例如{ default: 11 }
)來指定預設值。其他選項包括:limit
和:null
(例如{ limit: 50, null: false }
) – 詳情請參閱ActiveRecord::ConnectionAdapters::TableDefinition#column
。 -
add_foreign_key(from_table, to_table, options)
:新增一個新的外鍵。from_table
是具有鍵欄位的表格,to_table
包含參考的主鍵。 -
add_index(table_name, column_names, options)
:使用欄位名稱新增一個新的索引。其他選項包括:name
、:unique
(例如{ name: 'users_name_index', unique: true }
)和:order
(例如{ order: { name: :desc } }
)。 -
add_reference(:table_name, :reference_name)
:新增一個新的欄位,預設情況下為reference_name_id
,類型為整數。詳情請參閱ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference
。 -
add_timestamps(table_name, options)
:將時間戳記(created_at
和updated_at
)欄位新增到table_name
。
修改
-
change_column(table_name, column_name, type, options)
:使用與 add_column 相同的參數將欄位更改為不同的類型。 -
change_column_default(table_name, column_name, default_or_changes)
:在table_name
上設定由default_or_changes
定義的column_name
的預設值。傳遞包含:from
和:to
作為default_or_changes
的散列將使此更改在遷移中可逆。 -
change_column_null(table_name, column_name, null, default = nil)
:在column_name
上設定或移除NOT NULL
約束。null
旗標指示該值是否可以為NULL
。詳情請參閱ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null
。 -
change_table(name, options)
:允許對名為name
的表格進行欄位更改。它使表格物件可供一個區塊使用,該區塊可以向其中新增/移除欄位、索引或外鍵。 -
rename_column(table_name, column_name, new_column_name)
:重新命名欄位,但保留類型和內容。 -
rename_index(table_name, old_name, new_name)
:重新命名索引。 -
rename_table(old_name, new_name)
:將名為old_name
的表格重新命名為new_name
。
刪除
-
drop_table(*names)
:刪除指定的表格。 -
drop_join_table(table_1, table_2, options)
:刪除由指定參數指定的連接表格。 -
remove_column(table_name, column_name, type, options)
:從名為table_name
的表格中移除名為column_name
的欄位。 -
remove_columns(table_name, *column_names)
:從表格定義中移除指定的欄位。 -
remove_foreign_key(from_table, to_table = nil, **options)
:從名為table_name
的表格中移除指定的外鍵。 -
remove_index(table_name, column: column_names)
:移除由column_names
指定的索引。 -
remove_index(table_name, name: index_name)
:移除由index_name
指定的索引。 -
remove_reference(table_name, ref_name, options)
:移除由ref_name
指定的table_name
上的參考。 -
remove_timestamps(table_name, options)
:從表格定義中移除時間戳記欄位(created_at
和updated_at
)。
不可逆的轉換
某些轉換的破壞性無法逆轉。這種遷移應在其 down
方法中引發 ActiveRecord::IrreversibleMigration
例外。
從 Rails 內部執行遷移
Rails 套件有幾個工具可以幫助建立和應用遷移。
要生成新的遷移,您可以使用
$ bin/rails generate migration MyNewMigration
其中 MyNewMigration 是遷移的名稱。生成器將在 db/migrate/
目錄中建立一個空的遷移檔案 timestamp_my_new_migration.rb
,其中 timestamp
是生成遷移的 UTC 格式日期和時間。
有一個特殊的語法捷徑可以生成將欄位新增到表格的遷移。
$ bin/rails generate migration add_fieldname_to_tablename fieldname:string
這將生成檔案 timestamp_add_fieldname_to_tablename.rb
,如下所示
class AddFieldnameToTablename < ActiveRecord::Migration[8.0]
def change
add_column :tablenames, :fieldname, :string
end
end
要針對目前設定的資料庫執行遷移,請使用 bin/rails db:migrate
。這將透過執行所有待處理的遷移來更新資料庫,如果缺少,則建立 schema_migrations
表格(請參閱下面的「關於 schema_migrations 表格」部分)。它還將呼叫 db:schema:dump 命令,該命令將更新您的 db/schema.rb 檔案以匹配資料庫的結構。
要將資料庫回滾到先前的遷移版本,請使用 bin/rails db:rollback VERSION=X
,其中 X
是您希望降級到的版本。或者,如果您希望回滾最後幾次遷移,也可以使用 STEP 選項。 bin/rails db:rollback STEP=2
將回滾最新的兩次遷移。
如果有任何遷移引發 ActiveRecord::IrreversibleMigration
例外,則該步驟將失敗,您將需要執行一些手動操作。
更多範例
並非所有遷移都會更改結構描述。有些只是修復資料
class RemoveEmptyTags < ActiveRecord::Migration[8.0]
def up
Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
end
def down
# not much we can do to restore deleted data
raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
end
end
其他遷移在向上遷移而不是向下遷移時移除欄位
class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[8.0]
def up
remove_column :items, :incomplete_items_count
remove_column :items, :completed_items_count
end
def down
add_column :items, :incomplete_items_count
add_column :items, :completed_items_count
end
end
有時您需要使用 SQL 執行一些未由遷移直接抽象的操作
class MakeJoinUnique < ActiveRecord::Migration[8.0]
def up
execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
end
def down
execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
end
end
更改表格後使用模型
有時您會希望在遷移中添加一個欄位並在之後立即填充它。在這種情況下,您需要呼叫 Base#reset_column_information
以確保模型具有添加新欄位後的最新欄位資料。範例
class AddPeopleSalary < ActiveRecord::Migration[8.0]
def up
add_column :people, :salary, :integer
Person.reset_column_information
Person.all.each do |p|
p.update_attribute :salary, SalaryCalculator.compute(p)
end
end
end
控制詳細資訊
預設情況下,遷移將描述它們正在執行的操作,將它們寫入控制台,以及描述每個步驟花費多長時間的基準測試。
您可以透過設定 ActiveRecord::Migration.verbose = false
來使其靜默。
您也可以使用 say_with_time
方法插入您自己的訊息和基準測試
def up
...
say_with_time "Updating salaries..." do
Person.all.each do |p|
p.update_attribute :salary, SalaryCalculator.compute(p)
end
end
...
end
然後將列印短語「正在更新薪水...」,以及區塊完成時的區塊基準測試。
帶時間戳記的遷移
預設情況下,Rails 會生成如下所示的遷移
20080717013526_your_migration_name.rb
前綴是生成時間戳記(以 UTC 為單位)。不應手動修改時間戳記。要驗證遷移時間戳記是否符合 Active Record 預期的格式,您可以使用以下設定選項
config.active_record.validate_migration_timestamps = true
如果您希望使用數字前綴,則可以透過設定來關閉帶時間戳記的遷移
config.active_record.timestamped_migrations = false
在 application.rb 中。
可逆遷移
可逆遷移是可以知道如何為您執行 down
的遷移。您只需提供 up
邏輯,Migration
系統就會找出如何為您執行 down 命令。
要定義可逆遷移,請在遷移中定義 change
方法,如下所示
class TenderloveMigration < ActiveRecord::Migration[8.0]
def change
create_table(:horses) do |t|
t.column :content, :text
t.column :remind_at, :datetime
end
end
end
此遷移將在向上遷移時為您建立 horses 表格,並自動找出如何在向下遷移時刪除表格。
某些命令無法逆轉。如果您希望定義如何在這些情況下向上和向下移動,則應像以前一樣定義 up
和 down
方法。
如果命令無法逆轉,則在遷移向下移動時將引發 ActiveRecord::IrreversibleMigration
例外。
有關可逆命令的清單,請參閱 ActiveRecord::Migration::CommandRecorder
。
交易式遷移
如果資料庫適配器支援 DDL 交易,則所有遷移將自動包裝在交易中。但是,有些查詢您無法在交易內執行,對於這些情況,您可以關閉自動交易。
class ChangeEnum < ActiveRecord::Migration[8.0]
disable_ddl_transaction!
def up
execute "ALTER TYPE model_size ADD VALUE 'new_value'"
end
end
請記住,即使您在使用 self.disable_ddl_transaction!
的 Migration
中,您仍然可以開啟自己的交易。
- 模組 ActiveRecord::Migration::Compatibility
- 類別 ActiveRecord::Migration::CheckPending
- 類別 ActiveRecord::Migration::CommandRecorder
- #
- A
- C
- D
- E
- L
- M
- N
- P
- R
- S
- U
- V
- W
屬性(Attributes)
[讀寫]([RW]) | 名稱(name) | |
[讀寫]([RW]) | 版本(version) |
類別公開方法(Class Public methods)
[](version) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 629 def self.[](version) Compatibility.find(version) end
check_all_pending!() 連結(Link)
如果在某個環境中所有資料庫設定都有任何待處理的遷移,則會引發 ActiveRecord::PendingMigrationError 錯誤。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 693 def check_all_pending! pending_migrations = [] ActiveRecord::Tasks::DatabaseTasks.with_temporary_pool_for_each(env: env) do |pool| if pending = pool.migration_context.open.pending_migrations pending_migrations << pending end end migrations = pending_migrations.flatten if migrations.any? raise ActiveRecord::PendingMigrationError.new(pending_migrations: migrations) end end
current_version() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 633 def self.current_version ActiveRecord::VERSION::STRING.to_f end
disable_ddl_transaction!() 連結(Link)
停用包裝此遷移的事務。即使在呼叫 disable_ddl_transaction! 之後,您仍然可以建立自己的事務。
更多詳細資訊,請閱讀上方「事務性遷移(Transactional Migrations)」章節。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 735 def disable_ddl_transaction! @disable_ddl_transaction = true end
load_schema_if_pending!() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 709 def load_schema_if_pending! if any_schema_needs_update? load_schema! end check_pending_migrations end
migrate(direction) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 727 def migrate(direction) new.migrate direction end
new(name = self.class.name, version = nil) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 800 def initialize(name = self.class.name, version = nil) @name = name @version = version @connection = nil @pool = nil end
verbose 連結(Link)
指定遷移是否將執行的動作以及描述每個步驟花費時間的基準測試寫入到控制台。預設值為 true。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 797 cattr_accessor :verbose
實例公開方法(Instance Public methods)
announce(message) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1005 def announce(message) text = "#{version} #{name}: #{message}" length = [0, 75 - text.length].max write "== %s %s" % [text, "=" * length] end
connection() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1036 def connection @connection || ActiveRecord::Tasks::DatabaseTasks.migration_connection end
connection_pool() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1040 def connection_pool @pool || ActiveRecord::Tasks::DatabaseTasks.migration_connection_pool end
copy(destination, sources, options = {}) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1061 def copy(destination, sources, options = {}) copied = [] FileUtils.mkdir_p(destination) unless File.exist?(destination) schema_migration = SchemaMigration::NullSchemaMigration.new internal_metadata = InternalMetadata::NullInternalMetadata.new destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration, internal_metadata).migrations last = destination_migrations.last sources.each do |scope, path| source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration, internal_metadata).migrations source_migrations.each do |migration| source = File.binread(migration.filename) inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n" magic_comments = +"" loop do # If we have a magic comment in the original migration, # insert our comment after the first newline(end of the magic comment line) # so the magic keep working. # Note that magic comments must be at the first line(except sh-bang). source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment| magic_comments << magic_comment; "" end || break end if !magic_comments.empty? && source.start_with?("\n") magic_comments << "\n" source = source[1..-1] end source = "#{magic_comments}#{inserted_comment}#{source}" if duplicate = destination_migrations.detect { |m| m.name == migration.name } if options[:on_skip] && duplicate.scope != scope.to_s options[:on_skip].call(scope, migration) end next end migration.version = next_migration_number(last ? last.version + 1 : 0).to_i new_path = File.join(destination, "#{migration.version}_#{migration.name.underscore}.#{scope}.rb") old_path, migration.filename = migration.filename, new_path last = migration File.binwrite(migration.filename, source) copied << migration options[:on_copy].call(scope, migration, old_path) if options[:on_copy] destination_migrations << migration end end copied end
down() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 957 def down self.class.delegate = self return unless self.class.respond_to?(:down) self.class.down end
exec_migration(conn, direction) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 985 def exec_migration(conn, direction) @connection = conn if respond_to?(:change) if direction == :down revert { change } else change end else public_send(direction) end ensure @connection = nil @execution_strategy = nil end
execution_strategy() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 807 def execution_strategy @execution_strategy ||= ActiveRecord.migration_strategy.new(self) end
method_missing(method, *arguments, &block) 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1044 def method_missing(method, *arguments, &block) say_with_time "#{method}(#{format_arguments(arguments)})" do unless connection.respond_to? :revert unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method) arguments[0] = proper_table_name(arguments.first, table_name_options) if method == :rename_table || (method == :remove_foreign_key && !arguments.second.is_a?(Hash)) arguments[1] = proper_table_name(arguments.second, table_name_options) end end end return super unless execution_strategy.respond_to?(method) execution_strategy.send(method, *arguments, &block) end end
migrate(direction) 連結(Link)
在指定的方向執行此遷移
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 964 def migrate(direction) return unless respond_to?(direction) case direction when :up then announce "migrating" when :down then announce "reverting" end time_elapsed = nil ActiveRecord::Tasks::DatabaseTasks.migration_connection.pool.with_connection do |conn| time_elapsed = ActiveSupport::Benchmark.realtime do exec_migration(conn, direction) end end case direction when :up then announce "migrated (%.4fs)" % time_elapsed; write when :down then announce "reverted (%.4fs)" % time_elapsed; write end end
next_migration_number(number) 連結(Link)
決定下一個遷移的版本號碼。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1128 def next_migration_number(number) if ActiveRecord.timestamped_migrations [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max else "%.3d" % number.to_i end end
proper_table_name(name, options = {}) 連結(Link)
給定一個 Active Record 物件,找出正確的表格名稱。使用 Active Record 物件本身的 table_name,或傳入選項中的前綴/後綴。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1119 def proper_table_name(name, options = {}) if name.respond_to? :table_name name.table_name else "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}" end end
reversible() 連結(Link)
用於指定可以在一個方向或另一個方向執行的操作。呼叫傳入物件的 `up` 和 `down` 方法,僅在一個給定方向執行程式碼區塊。整個程式碼區塊將在遷移中以正確的順序呼叫。
在以下範例中,即使向下遷移,在 `first_name`、`last_name` 和 `full_name` 三個欄位存在時,始終會執行 users 的迴圈。
class SplitNameMigration < ActiveRecord::Migration[8.0]
def change
add_column :users, :first_name, :string
add_column :users, :last_name, :string
reversible do |dir|
User.reset_column_information
User.all.each do |u|
dir.up { u.first_name, u.last_name = u.full_name.split(' ') }
dir.down { u.full_name = "#{u.first_name} #{u.last_name}" }
u.save
end
end
revert { add_column :users, :full_name, :string }
end
end
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 909 def reversible helper = ReversibleBlockHelper.new(reverting?) execute_block { yield helper } end
revert(*migration_classes, &block) 連結(Link)
反轉給定程式碼區塊和給定遷移的遷移指令。
以下遷移將在向上遷移時移除 `horses` 表格並建立 `apples` 表格,並在向下遷移時執行相反操作。
class FixTLMigration < ActiveRecord::Migration[8.0]
def change
revert do
create_table(:horses) do |t|
t.text :content
t.datetime :remind_at
end
end
create_table(:apples) do |t|
t.string :variety
end
end
end
或者,如果 `TenderloveMigration` 的定義如 Migration 文件中所示,則等效於:
require_relative "20121212123456_tenderlove_migration"
class FixupTLMigration < ActiveRecord::Migration[8.0]
def change
revert TenderloveMigration
create_table(:apples) do |t|
t.string :variety
end
end
end
此指令可以巢狀。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 852 def revert(*migration_classes, &block) run(*migration_classes.reverse, revert: true) unless migration_classes.empty? if block_given? if connection.respond_to? :revert connection.revert(&block) else recorder = command_recorder @connection = recorder suppress_messages do connection.revert(&block) end @connection = recorder.delegate recorder.replay(self) end end end
reverting?() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 869 def reverting? connection.respond_to?(:reverting) && connection.reverting end
run(*migration_classes) 連結(Link)
執行給定的遷移類別。最後一個參數可以指定選項
-
`:direction` - 預設值為 `:up`。
-
`:revert` - 預設值為 `false`。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 937 def run(*migration_classes) opts = migration_classes.extract_options! dir = opts[:direction] || :up dir = (dir == :down ? :up : :down) if opts[:revert] if reverting? # If in revert and going :up, say, we want to execute :down without reverting, so revert { run(*migration_classes, direction: dir, revert: true) } else migration_classes.each do |migration_class| migration_class.new.exec_migration(connection, dir) end end end
say(message, subitem = false) 連結(Link)
接受一個訊息參數並按原樣輸出。可以傳遞第二個布林值參數來指定是否縮排。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1013 def say(message, subitem = false) write "#{subitem ? " ->" : "--"} #{message}" end
say_with_time(message) 連結(Link)
輸出文字以及執行其程式碼區塊所花費的時間。如果程式碼區塊傳回一個整數,則假定它是受影響的列數。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1019 def say_with_time(message) say(message) result = nil time_elapsed = ActiveSupport::Benchmark.realtime { result = yield } say "%.4fs" % time_elapsed, :subitem say("#{result} rows", :subitem) if result.is_a?(Integer) result end
suppress_messages() 連結(Link)
接受一個程式碼區塊作為參數,並抑制程式碼區塊產生的任何輸出。
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1029 def suppress_messages save, self.verbose = verbose, false yield ensure self.verbose = save end
up() 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 951 def up self.class.delegate = self return unless self.class.respond_to?(:up) self.class.up end
up_only(&block) 連結(Link)
用於指定僅在向上遷移時執行的操作(例如,使用初始值填充新欄位)。
在以下範例中,新欄位 `published` 將為所有現有記錄賦予值 `true`。
class AddPublishedToPosts < ActiveRecord::Migration[8.0]
def change
add_column :posts, :published, :boolean, default: false
up_only do
execute "update posts set published = 'true'"
end
end
end
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 928 def up_only(&block) execute_block(&block) unless reverting? end
write(text = "") 連結(Link)
來源:顯示(show) | 在 GitHub 上(on GitHub)
# File activerecord/lib/active_record/migration.rb, line 1001 def write(text = "") puts(text) if verbose end