跳至内容 跳至搜索

Active Record 数据库任务

ActiveRecord::Tasks::DatabaseTasks 是一个实用程序类,封装了用于管理数据库和迁移的常见任务背后的逻辑。

此处定义的任务与 Active Record 提供的 Rails 命令一起使用。

为了使用 DatabaseTasks,需要设置一些配置值。所有必要的配置值都由 Rails 已经设置,所以只有当你想要更改默认值或者当你想要在 Rails 之外使用 Active Record 时才需要设置它(在这种情况下,在配置数据库任务后,你也可以使用 Active Record 中定义的 rake 任务)。

可能的配置值是

  • env:当前环境(如 Rails.env)。

  • database_configuration:你的数据库的配置(如 config/database.yml)。

  • db_dir:你的 db 目录。

  • fixtures_path:一个指向 fixtures 目录的路径。

  • migrations_paths:一个指向包含迁移的目录的路径列表。

  • seed_loader:一个将加载 seed 的对象,它需要响应 load_seed 方法。

  • root:一个指向应用程序根目录的路径。

在 Rails 之外使用 DatabaseTasks 的示例用法可能如下所示

include ActiveRecord::Tasks
DatabaseTasks.database_configuration = YAML.load_file('my_database_config.yml')
DatabaseTasks.db_dir = 'db'
# other settings...

DatabaseTasks.create_current('production')
方法
C
D
E
F
L
M
N
P
R
S
T

常量

LOCAL_HOSTS = ["127.0.0.1", "localhost"]
 

属性

[RW] database_configuration
[W] db_dir
[W] env
[W] fixtures_path
[W] migrations_paths
[W] root
[W] seed_loader

类公共方法

structure_dump_flags

调用 db:schema:dump 时传递给数据库 CLI 工具(mysqldump/pg_dump)的额外标志。它可以用作字符串/数组(典型情况)或哈希(当你使用多个适配器时)。示例

ActiveRecord::Tasks::DatabaseTasks.structure_dump_flags = {
  mysql2: ['--no-defaults', '--skip-add-drop-table'],
  postgres: '--no-tablespaces'
}
# File activerecord/lib/active_record/tasks/database_tasks.rb, line 50
mattr_accessor :structure_dump_flags, instance_accessor: false

structure_load_flags

调用 db:schema:load 时传递给数据库 CLI 工具的额外标志。它可以用作字符串/数组(典型情况)或哈希(当你使用多个适配器时)。

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 56
mattr_accessor :structure_load_flags, instance_accessor: false

实例公共方法

cache_dump_filename(db_config, schema_cache_path: nil)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 468
def cache_dump_filename(db_config, schema_cache_path: nil)
  schema_cache_path ||
    db_config.schema_cache_path ||
    db_config.default_schema_cache_path(ActiveRecord::Tasks::DatabaseTasks.db_dir)
end

charset(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 332
def charset(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config, *arguments).charset
end

charset_current(env_name = env, db_name = name)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 327
def charset_current(env_name = env, db_name = name)
  db_config = configs_for(env_name: env_name, name: db_name)
  charset(db_config)
end

check_protected_environments!(environment = env)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 65
def check_protected_environments!(environment = env)
  return if ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]

  configs_for(env_name: environment).each do |db_config|
    check_current_protected_environment!(db_config)
  end
end

check_schema_file(filename)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 482
def check_schema_file(filename)
  unless File.exist?(filename)
    message = +%{#{filename} doesn't exist yet. Run `bin/rails db:migrate` to create it, then try again.}
    message << %{ If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded.} if defined?(::Rails.root)
    Kernel.abort message
  end
end

check_target_version()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 317
def check_target_version
  if target_version && !Migration.valid_version_format?(ENV["VERSION"])
    raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
  end
end

clear_schema_cache(filename)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 508
def clear_schema_cache(filename)
  FileUtils.rm_f filename, verbose: false
end

collation(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 342
def collation(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config, *arguments).collation
end

collation_current(env_name = env, db_name = name)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 337
def collation_current(env_name = env, db_name = name)
  db_config = configs_for(env_name: env_name, name: db_name)
  collation(db_config)
end

create(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 115
def create(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config, *arguments).create
  $stdout.puts "Created database '#{db_config.database}'" if verbose?
rescue DatabaseAlreadyExists
  $stderr.puts "Database '#{db_config.database}' already exists" if verbose?
rescue Exception => error
  $stderr.puts error
  $stderr.puts "Couldn't create '#{db_config.database}' database. Please check your configuration."
  raise
end

create_all()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 127
def create_all
  db_config = migration_connection.pool.db_config

  each_local_configuration { |db_config| create(db_config) }

  migration_class.establish_connection(db_config)
end

create_current(environment = env, name = nil)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 170
def create_current(environment = env, name = nil)
  each_current_configuration(environment, name) { |db_config| create(db_config) }

  migration_class.establish_connection(environment.to_sym)
end

db_dir()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 83
def db_dir
  @db_dir ||= Rails.application.config.paths["db"].first
end

drop(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 210
def drop(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config, *arguments).drop
  $stdout.puts "Dropped database '#{db_config.database}'" if verbose?
rescue ActiveRecord::NoDatabaseError
  $stderr.puts "Database '#{db_config.database}' does not exist"
rescue Exception => error
  $stderr.puts error
  $stderr.puts "Couldn't drop database '#{db_config.database}'"
  raise
end

drop_all()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 222
def drop_all
  each_local_configuration { |db_config| drop(db_config) }
end

drop_current(environment = env)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 226
def drop_current(environment = env)
  each_current_configuration(environment) { |db_config| drop(db_config) }
end

dump_schema_cache(conn_or_pool, filename)

将连接的 schema 缓存以 YAML 格式转储到文件中

示例

ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.lease_connection, "tmp/schema_dump.yaml")
# File activerecord/lib/active_record/tasks/database_tasks.rb, line 504
def dump_schema_cache(conn_or_pool, filename)
  conn_or_pool.schema_cache.dump_to(filename)
end

env()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 103
def env
  @env ||= Rails.env
end

fixtures_path()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 91
def fixtures_path
  @fixtures_path ||= if ENV["FIXTURES_PATH"]
    File.join(root, ENV["FIXTURES_PATH"])
  else
    File.join(root, "test", "fixtures")
  end
end

load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 474
def load_schema_current(format = ActiveRecord.schema_format, file = nil, environment = env)
  each_current_configuration(environment) do |db_config|
    with_temporary_connection(db_config) do
      load_schema(db_config, format, file)
    end
  end
end

load_seed()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 490
def load_seed
  if seed_loader
    seed_loader.load_seed
  else
    raise "You tried to load seed data, but no seed loader is specified. Please specify seed " \
          "loader with ActiveRecord::Tasks::DatabaseTasks.seed_loader = your_seed_loader\n" \
          "Seed loader should respond to load_seed method"
  end
end

migrate(version = nil, skip_initialize: false)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 262
def migrate(version = nil, skip_initialize: false)
  scope = ENV["SCOPE"]
  verbose_was, Migration.verbose = Migration.verbose, verbose?

  check_target_version

  initialize_database(migration_connection_pool.db_config) unless skip_initialize

  migration_connection_pool.migration_context.migrate(target_version) do |migration|
    if version.blank?
      scope.blank? || scope == migration.scope
    else
      migration.version == version
    end
  end.tap do |migrations_ran|
    Migration.write("No migrations ran. (using #{scope} scope)") if scope.present? && migrations_ran.empty?
  end

  migration_connection_pool.schema_cache.clear!
ensure
  Migration.verbose = verbose_was
end

migrate_all()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 243
def migrate_all
  db_configs = ActiveRecord::Base.configurations.configs_for(env_name: ActiveRecord::Tasks::DatabaseTasks.env)
  db_configs.each { |db_config| initialize_database(db_config) }

  if db_configs.size == 1 && db_configs.first.primary?
    ActiveRecord::Tasks::DatabaseTasks.migrate(skip_initialize: true)
  else
    mapped_versions = ActiveRecord::Tasks::DatabaseTasks.db_configs_with_versions

    mapped_versions.sort.each do |version, db_configs|
      db_configs.each do |db_config|
        ActiveRecord::Tasks::DatabaseTasks.with_temporary_connection(db_config) do
          ActiveRecord::Tasks::DatabaseTasks.migrate(version, skip_initialize: true)
        end
      end
    end
  end
end

migrate_status()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 302
def migrate_status
  unless migration_connection_pool.schema_migration.table_exists?
    Kernel.abort "Schema migrations table does not exist yet."
  end

  # output
  puts "\ndatabase: #{migration_connection_pool.db_config.database}\n\n"
  puts "#{'Status'.center(8)}  #{'Migration ID'.ljust(14)}  Migration Name"
  puts "-" * 50
  migration_connection_pool.migration_context.migrations_status.each do |status, version, name|
    puts "#{status.center(8)}  #{version.ljust(14)}  #{name}"
  end
  puts
end

migrations_paths()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 87
def migrations_paths
  @migrations_paths ||= Rails.application.paths["db/migrate"].to_a
end

name()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 107
def name
  @name ||= "primary"
end

prepare_all()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 176
def prepare_all
  seed = false
  dump_db_configs = []

  each_current_configuration(env) do |db_config|
    database_initialized = initialize_database(db_config)

    seed = true if database_initialized && db_config.seeds?
  end

  each_current_environment(env) do |environment|
    db_configs_with_versions(environment).sort.each do |version, db_configs|
      dump_db_configs |= db_configs

      db_configs.each do |db_config|
        with_temporary_pool(db_config) do
          migrate(version)
        end
      end
    end
  end

  # Dump schema for databases that were migrated.
  if ActiveRecord.dump_schema_after_migration
    dump_db_configs.each do |db_config|
      with_temporary_pool(db_config) do
        dump_schema(db_config)
      end
    end
  end

  load_seed if seed
end

purge(configuration)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 347
def purge(configuration)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config).purge
end

purge_all()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 352
def purge_all
  each_local_configuration { |db_config| purge(db_config) }
end

purge_current(environment = env)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 356
def purge_current(environment = env)
  each_current_configuration(environment) { |db_config| purge(db_config) }

  migration_class.establish_connection(environment.to_sym)
end

register_task(pattern, task)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 73
def register_task(pattern, task)
  @tasks ||= {}
  @tasks[pattern] = task
end

root()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 99
def root
  @root ||= Rails.root
end

schema_dump_path(db_config, format = ActiveRecord.schema_format)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 455
def schema_dump_path(db_config, format = ActiveRecord.schema_format)
  return ENV["SCHEMA"] if ENV["SCHEMA"]

  filename = db_config.schema_dump(format)
  return unless filename

  if File.dirname(filename) == ActiveRecord::Tasks::DatabaseTasks.db_dir
    filename
  else
    File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
  end
end

schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 397
def schema_up_to_date?(configuration, format = ActiveRecord.schema_format, file = nil)
  db_config = resolve_configuration(configuration)

  file ||= schema_dump_path(db_config)

  return true unless file && File.exist?(file)

  with_temporary_pool(db_config) do |pool|
    internal_metadata = pool.internal_metadata
    return false unless internal_metadata.enabled?
    return false unless internal_metadata.table_exists?

    internal_metadata[:schema_sha1] == schema_sha1(file)
  end
end

seed_loader()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 111
def seed_loader
  @seed_loader ||= Rails.application
end

structure_dump(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 362
def structure_dump(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  filename = arguments.delete_at(0)
  flags = structure_dump_flags_for(db_config.adapter)
  database_adapter_for(db_config, *arguments).structure_dump(filename, flags)
end

structure_load(configuration, *arguments)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 369
def structure_load(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  filename = arguments.delete_at(0)
  flags = structure_load_flags_for(db_config.adapter)
  database_adapter_for(db_config, *arguments).structure_load(filename, flags)
end

target_version()

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 323
def target_version
  ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
end

truncate_all(environment = env)

# File activerecord/lib/active_record/tasks/database_tasks.rb, line 237
def truncate_all(environment = env)
  configs_for(env_name: environment).each do |db_config|
    truncate_tables(db_config)
  end
end