123456789_123456789_123456789_123456789_123456789_

Module: ActiveRecord::Tasks::DatabaseTasks

Relationships & Source Files
Defined in: activerecord/lib/active_record/tasks/database_tasks.rb

Overview

DatabaseTasks is a utility class, which encapsulates logic behind common tasks used to manage database and migrations.

The tasks defined here are used with ::Rails commands provided by Active Record.

In order to use DatabaseTasks, a few config values need to be set. All the needed config values are set by ::Rails already, so it’s necessary to do it only if you want to change the defaults or when you want to use Active Record outside of ::Rails (in such case after configuring the database tasks, you can also use the rake tasks defined in Active Record).

The possible config values are:

Example usage of DatabaseTasks outside ::Rails could look as such:

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

DatabaseTasks.create_current('production')

Constant Summary

Class Attribute Summary

Instance Attribute Summary

Instance Method Summary

Class Attribute Details

.structure_dump_flags (rw)

Extra flags passed to database CLI tool (mysqldump/pg_dump) when calling db:schema:dump

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 42

mattr_accessor :structure_dump_flags, instance_accessor: false

.structure_load_flags (rw)

Extra flags passed to database CLI tool when calling db:schema:load

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 47

mattr_accessor :structure_load_flags, instance_accessor: false

Instance Attribute Details

#current_config(options = {}) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 119

def current_config(options = {})
  if options.has_key?(:config)
    @current_config = options[:config]
  else
    env_name = options[:env] || env
    name = options[:spec] || "primary"

    @current_config ||= ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: name)&.configuration_hash
  end
end

#current_config=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#database_configuration (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 53

attr_accessor :database_configuration

#db_dir (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 82

def db_dir
  @db_dir ||= Rails.application.config.paths["db"].first
end

#db_dir=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#env (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 102

def env
  @env ||= Rails.env
end

#env=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#fixtures_path (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 90

def fixtures_path
  @fixtures_path ||= if ENV["FIXTURES_PATH"]
    File.join(root, ENV["FIXTURES_PATH"])
  else
    File.join(root, "test", "fixtures")
  end
end

#fixtures_path=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#migrations_paths (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 86

def migrations_paths
  @migrations_paths ||= Rails.application.paths["db/migrate"].to_a
end

#migrations_paths=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#root (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 98

def root
  @root ||= Rails.root
end

#root=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

#seed_loader (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 115

def seed_loader
  @seed_loader ||= Rails.application
end

#seed_loader=(value) (rw)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 51

attr_writer :current_config, :db_dir, :migrations_paths, :fixtures_path, :root, :env, :seed_loader

Instance Method Details

#cache_dump_filename(db_config_name, schema_cache_path: nil)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 423

def cache_dump_filename(db_config_name, schema_cache_path: nil)
  filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
    "schema_cache.yml"
  else
    "#{db_config_name}_schema_cache.yml"
  end

  schema_cache_path || ENV["SCHEMA_CACHE"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
end

#charset(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 276

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)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 271

def charset_current(env_name = env, db_name = name)
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
  charset(db_config)
end

#check_protected_environments!

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 57

def check_protected_environments!
  unless ENV["DISABLE_DATABASE_ENVIRONMENT_CHECK"]
    current = ActiveRecord::Base.connection.migration_context.current_environment
    stored  = ActiveRecord::Base.connection.migration_context.last_stored_environment

    if ActiveRecord::Base.connection.migration_context.protected_environment?
      raise ActiveRecord::ProtectedEnvironmentError.new(stored)
    end

    if stored && stored != current
      raise ActiveRecord::EnvironmentMismatchError.new(current: current, stored: stored)
    end
  end
rescue ActiveRecord::NoDatabaseError
end

#check_schema_file(filename)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 440

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

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 261

def check_target_version
  if target_version && !(Migration::MigrationFilenameRegexp.match?(ENV["VERSION"]) || /\A\d+\z/.match?(ENV["VERSION"]))
    raise "Invalid format of target version: `VERSION=#{ENV['VERSION']}`"
  end
end

#clear_schema_cache(filename)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 466

def clear_schema_cache(filename)
  FileUtils.rm_f filename, verbose: false
end

#collation(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 286

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)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 281

def collation_current(env_name = env, db_name = name)
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: env_name, name: db_name)
  collation(db_config)
end

#create(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 131

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

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 143

def create_all
  old_pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(ActiveRecord::Base.connection_specification_name)
  each_local_configuration { |db_config| create(db_config) }
  if old_pool
    ActiveRecord::Base.connection_handler.establish_connection(old_pool.db_config)
  end
end

#create_current(environment = env, name = nil)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 192

def create_current(environment = env, name = nil)
  each_current_configuration(environment, name) { |db_config| create(db_config) }
  ActiveRecord::Base.establish_connection(environment.to_sym)
end

#drop(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 197

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

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 209

def drop_all
  each_local_configuration { |db_config| drop(db_config) }
end

#drop_current(environment = env)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 213

def drop_current(environment = env)
  each_current_configuration(environment) { |db_config| drop(db_config) }
end

#dump_filename(db_config_name, format = ActiveRecord::Base.schema_format)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 413

def dump_filename(db_config_name, format = ActiveRecord::Base.schema_format)
  filename = if ActiveRecord::Base.configurations.primary?(db_config_name)
    schema_file_type(format)
  else
    "#{db_config_name}_#{schema_file_type(format)}"
  end

  ENV["SCHEMA"] || File.join(ActiveRecord::Tasks::DatabaseTasks.db_dir, filename)
end

#dump_schema_cache(conn, filename)

Dumps the schema cache in YAML format for the connection into the file

Examples:

ActiveRecord::Tasks::DatabaseTasks.dump_schema_cache(ActiveRecord::Base.connection, "tmp/schema_dump.yaml")
[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 462

def dump_schema_cache(conn, filename)
  conn.schema_cache.dump_to(filename)
end

#for_each(databases)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 165

def for_each(databases)
  return {} unless defined?(Rails)

  database_configs = ActiveRecord::DatabaseConfigurations.new(databases).configs_for(env_name: Rails.env)

  # if this is a single database application we don't want tasks for each primary database
  return if database_configs.count == 1

  database_configs.each do |db_config|
    yield db_config.name
  end
end

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

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 433

def load_schema_current(format = ActiveRecord::Base.schema_format, file = nil, environment = env)
  each_current_configuration(environment) do |db_config|
    load_schema(db_config, format, file)
  end
  ActiveRecord::Base.establish_connection(environment.to_sym)
end

#load_seed

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 448

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

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 231

def migrate
  check_target_version

  scope = ENV["SCOPE"]
  verbose_was, Migration.verbose = Migration.verbose, verbose?

  Base.connection.migration_context.migrate(target_version) do |migration|
    scope.blank? || scope == migration.scope
  end

  ActiveRecord::Base.clear_cache!
ensure
  Migration.verbose = verbose_was
end

#migrate_status

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 246

def migrate_status
  unless ActiveRecord::Base.connection.schema_migration.table_exists?
    Kernel.abort "Schema migrations table does not exist yet."
  end

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

#name

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 111

def name
  @name ||= "primary"
end

#purge(configuration)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 291

def purge(configuration)
  db_config = resolve_configuration(configuration)
  database_adapter_for(db_config).purge
end

#purge_all

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 296

def purge_all
  each_local_configuration { |db_config| purge(db_config) }
end

#purge_current(environment = env)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 300

def purge_current(environment = env)
  each_current_configuration(environment) { |db_config| purge(db_config) }
  ActiveRecord::Base.establish_connection(environment.to_sym)
end

#raise_for_multi_db(environment = env, command:)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 178

def raise_for_multi_db(environment = env, command:)
  db_configs = ActiveRecord::Base.configurations.configs_for(env_name: environment)

  if db_configs.count > 1
    dbs_list = []

    db_configs.each do |db|
      dbs_list << "#{command}:#{db.name}"
    end

    raise "You're using a multiple database application. To use `#{command}` you must run the namespaced task with a VERSION. Available tasks are #{dbs_list.to_sentence}."
  end
end

#register_task(pattern, task)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 73

def register_task(pattern, task)
  @tasks ||= {}
  @tasks[pattern] = task
end

#schema_file(format = ActiveRecord::Base.schema_format)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 400

def schema_file(format = ActiveRecord::Base.schema_format)
  File.join(db_dir, schema_file_type(format))
end

#schema_file_type(format = ActiveRecord::Base.schema_format)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 404

def schema_file_type(format = ActiveRecord::Base.schema_format)
  case format
  when :ruby
    "schema.rb"
  when :sql
    "structure.sql"
  end
end

#schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = nil, name = nil) ⇒ Boolean

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 339

def schema_up_to_date?(configuration, format = ActiveRecord::Base.schema_format, file = nil, environment = nil, name = nil)
  db_config = resolve_configuration(configuration)

  if environment || name
    ActiveSupport::Deprecation.warn("`environment` and `name` will be removed as parameters in 7.0.0, you may now pass an ActiveRecord::DatabaseConfigurations::DatabaseConfig as `configuration` instead.")
  end

  name ||= db_config.name

  file ||= dump_filename(name, format)

  return true unless File.exist?(file)

  ActiveRecord::Base.establish_connection(db_config)

  return false unless ActiveRecord::InternalMetadata.enabled?
  return false unless ActiveRecord::InternalMetadata.table_exists?

  ActiveRecord::InternalMetadata[:schema_sha1] == schema_sha1(file)
end

#setup_initial_database_yaml

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 151

def setup_initial_database_yaml
  return {} unless defined?(Rails)

  begin
    Rails.application.config.load_database_yaml
  rescue
    unless ActiveRecord::Base.suppress_multiple_database_warning
      $stderr.puts "Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB."
    end

    {}
  end
end

#spec

Deprecated.

please use name instead

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 106

def spec
  @spec ||= "primary"
end

#structure_dump(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 305

def structure_dump(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  filename = arguments.delete_at(0)
  database_adapter_for(db_config, *arguments).structure_dump(filename, structure_dump_flags)
end

#structure_load(configuration, *arguments)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 311

def structure_load(configuration, *arguments)
  db_config = resolve_configuration(configuration)
  filename = arguments.delete_at(0)
  database_adapter_for(db_config, *arguments).structure_load(filename, structure_load_flags)
end

#target_version

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 267

def target_version
  ENV["VERSION"].to_i if ENV["VERSION"] && !ENV["VERSION"].empty?
end

#truncate_all(environment = env)

[ GitHub ]

  
# File 'activerecord/lib/active_record/tasks/database_tasks.rb', line 225

def truncate_all(environment = env)
  ActiveRecord::Base.configurations.configs_for(env_name: environment).each do |db_config|
    truncate_tables(db_config)
  end
end