Methods

Constants

DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }
RAILS_ENV = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"].presence || ENV["RACK_ENV"].presence }

Attributes

[W] connection_specification_name

Instance Public methods

clear_query_caches_for_current_thread()

Clears the query cache for all connections associated with the current thread.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 269
    def clear_query_caches_for_current_thread
      if ActiveRecord::Base.legacy_connection_handling
        ActiveRecord::Base.connection_handlers.each_value do |handler|
          clear_on_handler(handler)
        end
      else
        clear_on_handler(ActiveRecord::Base.connection_handler)
      end
    end
πŸ”Ž See on GitHub

connected?()

Returns true if Active Record is connected.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 331
    def connected?
      connection_handler.connected?(connection_specification_name, role: current_role, shard: current_shard)
    end
πŸ”Ž See on GitHub

connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)

Connects to a role (ex writing, reading or a custom role) and/or shard for the duration of the block. At the end of the block the connection will be returned to the original role / shard.

If only a role is passed, Active Record will look up the connection based on the requested role. If a non-established role is requested an ActiveRecord::ConnectionNotEstablished error will be raised:

ActiveRecord::Base.connected_to(role: :writing) do
  Dog.create! # creates dog using dog writing connection
end

ActiveRecord::Base.connected_to(role: :reading) do
  Dog.create! # throws exception because we're on a replica
end

When swapping to a shard, the role must be passed as well. If a non-existent shard is passed, an ActiveRecord::ConnectionNotEstablished error will be raised.

When a shard and role is passed, Active Record will first lookup the role, and then look up the connection by shard key.

ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one_replica) do
  Dog.first # finds first Dog record stored on the shard one replica
end

The database kwarg is deprecated and will be removed in Rails 7.0.0 without replacement.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 139
    def connected_to(database: nil, role: nil, shard: nil, prevent_writes: false, &blk)
      if legacy_connection_handling
        if self != Base
          raise NotImplementedError, "`connected_to` can only be called on ActiveRecord::Base with legacy connection handling."
        end
      else
        if self != Base && !abstract_class
          raise NotImplementedError, "calling `connected_to` is only allowed on ActiveRecord::Base or abstract classes."
        end

        if name != connection_specification_name && !primary_class?
          raise NotImplementedError, "calling `connected_to` is only allowed on the abstract class that established the connection."
        end
      end

      if database && (role || shard)
        raise ArgumentError, "`connected_to` cannot accept a `database` argument with any other arguments."
      elsif database
        ActiveSupport::Deprecation.warn("The database key in `connected_to` is deprecated. It will be removed in Rails 7.0.0 without replacement.")

        if database.is_a?(Hash)
          role, database = database.first
          role = role.to_sym
        end

        db_config, owner_name = resolve_config_for_connection(database)
        handler = lookup_connection_handler(role)

        handler.establish_connection(db_config, owner_name: owner_name, role: role)

        with_handler(role, &blk)
      elsif role || shard
        unless role
          raise ArgumentError, "`connected_to` cannot accept a `shard` argument without a `role`."
        end

        with_role_and_shard(role, shard, prevent_writes, &blk)
      else
        raise ArgumentError, "must provide a `shard` and/or `role`."
      end
    end
πŸ”Ž See on GitHub

connected_to?(role:, shard: ActiveRecord::Base.default_shard)

Returns true if role is the current connected role.

ActiveRecord::Base.connected_to(role: :writing) do
  ActiveRecord::Base.connected_to?(role: :writing) #=> true
  ActiveRecord::Base.connected_to?(role: :reading) #=> false
end
πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 255
    def connected_to?(role:, shard: ActiveRecord::Base.default_shard)
      current_role == role.to_sym && current_shard == shard.to_sym
    end
πŸ”Ž See on GitHub

connected_to_many(*classes, role:, shard: nil, prevent_writes: false)

Connects a role and/or shard to the provided connection names. Optionally prevent_writes can be passed to block writes on a connection. reading will automatically set prevent_writes to true.

connected_to_many is an alternative to deeply nested connected_to blocks.

Usage:

ActiveRecord::Base.connected_to_many(AnimalsRecord, MealsRecord, role: :reading) do
  Dog.first # Read from animals replica
  Dinner.first # Read from meals replica
  Person.first # Read from primary writer
end
πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 194
    def connected_to_many(*classes, role:, shard: nil, prevent_writes: false)
      classes = classes.flatten

      if legacy_connection_handling
        raise NotImplementedError, "connected_to_many is not available with legacy connection handling"
      end

      if self != Base || classes.include?(Base)
        raise NotImplementedError, "connected_to_many can only be called on ActiveRecord::Base."
      end

      prevent_writes = true if role == reading_role

      connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes }
      yield
    ensure
      connected_to_stack.pop
    end
πŸ”Ž See on GitHub

connecting_to(role: default_role, shard: default_shard, prevent_writes: false)

Use a specified connection.

This method is useful for ensuring that a specific connection is being used. For example, when booting a console in readonly mode.

It is not recommended to use this method in a request since it does not yield to a block like connected_to.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 220
    def connecting_to(role: default_role, shard: default_shard, prevent_writes: false)
      if legacy_connection_handling
        raise NotImplementedError, "`connecting_to` is not available with `legacy_connection_handling`."
      end

      prevent_writes = true if role == reading_role

      self.connected_to_stack << { role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self] }
    end
πŸ”Ž See on GitHub

connection()

Returns the connection currently associated with the class. This can also be used to β€œborrow” the connection to do database work unrelated to any of the specific Active Records.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 282
    def connection
      retrieve_connection
    end
πŸ”Ž See on GitHub

connection_config()

Returns the configuration of the associated connection as a hash:

ActiveRecord::Base.connection_config
# => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}

Please use only for reading.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 306
    def connection_config
      connection_pool.db_config.configuration_hash
    end
πŸ”Ž See on GitHub

connection_db_config()

Returns the db_config object from the associated connection:

ActiveRecord::Base.connection_db_config
  #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
    @name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>

Use only for reading.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 318
    def connection_db_config
      connection_pool.db_config
    end
πŸ”Ž See on GitHub

connection_pool()

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 322
    def connection_pool
      connection_handler.retrieve_connection_pool(connection_specification_name, role: current_role, shard: current_shard) || raise(ConnectionNotEstablished)
    end
πŸ”Ž See on GitHub

connection_specification_name()

Return the connection specification name from the current class or its parent.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 289
    def connection_specification_name
      if !defined?(@connection_specification_name) || @connection_specification_name.nil?
        return self == Base ? Base.name : superclass.connection_specification_name
      end
      @connection_specification_name
    end
πŸ”Ž See on GitHub

connects_to(database: {}, shards: {})

Connects a model to the databases specified. The database keyword takes a hash consisting of a role and a database_key.

This will create a connection handler for switching between connections, look up the config hash using the database_key and finally establishes a connection to that config.

class AnimalsModel < ApplicationRecord
  self.abstract_class = true

  connects_to database: { writing: :primary, reading: :primary_replica }
end

connects_to also supports horizontal sharding. The horizontal sharding API also supports read replicas. Connect a model to a list of shards like this:

class AnimalsModel < ApplicationRecord
  self.abstract_class = true

  connects_to shards: {
    default: { writing: :primary, reading: :primary_replica },
    shard_two: { writing: :primary_shard_two, reading: :primary_shard_replica_two }
  }
end

Returns an array of database connections.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 81
    def connects_to(database: {}, shards: {})
      raise NotImplementedError, "`connects_to` can only be called on ActiveRecord::Base or abstract classes" unless self == Base || abstract_class?

      if database.present? && shards.present?
        raise ArgumentError, "`connects_to` can only accept a `database` or `shards` argument, but not both arguments."
      end

      connections = []

      database.each do |role, database_key|
        db_config, owner_name = resolve_config_for_connection(database_key)
        handler = lookup_connection_handler(role.to_sym)

        self.connection_class = true
        connections << handler.establish_connection(db_config, owner_name: owner_name, role: role)
      end

      shards.each do |shard, database_keys|
        database_keys.each do |role, database_key|
          db_config, owner_name = resolve_config_for_connection(database_key)
          handler = lookup_connection_handler(role.to_sym)

          self.connection_class = true
          connections << handler.establish_connection(db_config, owner_name: owner_name, role: role, shard: shard.to_sym)
        end
      end

      connections
    end
πŸ”Ž See on GitHub

establish_connection(config_or_env = nil)

Establishes the connection to the database. Accepts a hash as input where the :adapter key must be specified with the name of a database adapter (in lower-case) example for regular databases (MySQL, PostgreSQL, etc):

ActiveRecord::Base.establish_connection(
  adapter:  "mysql2",
  host:     "localhost",
  username: "myuser",
  password: "mypass",
  database: "somedatabase"
)

Example for SQLite database:

ActiveRecord::Base.establish_connection(
  adapter:  "sqlite3",
  database: "path/to/dbfile"
)

Also accepts keys as strings (for parsing from YAML for example):

ActiveRecord::Base.establish_connection(
  "adapter"  => "sqlite3",
  "database" => "path/to/dbfile"
)

Or a URL:

ActiveRecord::Base.establish_connection(
  "postgres://myuser:mypass@localhost/somedatabase"
)

In case ActiveRecord::Base.configurations is set (Rails automatically loads the contents of config/database.yml into it), a symbol can also be given as argument, representing a key in the configuration hash:

ActiveRecord::Base.establish_connection(:production)

The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError may be returned on an error.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 49
    def establish_connection(config_or_env = nil)
      config_or_env ||= DEFAULT_ENV.call.to_sym
      db_config, owner_name = resolve_config_for_connection(config_or_env)
      connection_handler.establish_connection(db_config, owner_name: owner_name, role: current_role, shard: current_shard)
    end
πŸ”Ž See on GitHub

remove_connection(name = nil)

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 335
    def remove_connection(name = nil)
      name ||= @connection_specification_name if defined?(@connection_specification_name)
      # if removing a connection that has a pool, we reset the
      # connection_specification_name so it will use the parent
      # pool.
      if connection_handler.retrieve_connection_pool(name, role: current_role, shard: current_shard)
        self.connection_specification_name = nil
      end

      connection_handler.remove_connection_pool(name, role: current_role, shard: current_shard)
    end
πŸ”Ž See on GitHub

retrieve_connection()

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 326
    def retrieve_connection
      connection_handler.retrieve_connection(connection_specification_name, role: current_role, shard: current_shard)
    end
πŸ”Ž See on GitHub

while_preventing_writes(enabled = true, &block)

Prevent writing to the database regardless of role.

In some cases you may want to prevent writes to the database even if you are on a database that can write. while_preventing_writes will prevent writes to the database for the duration of the block.

This method does not provide the same protection as a readonly user and is meant to be a safeguard against accidental writes.

See READ_QUERY for the queries that are blocked by this method.

πŸ“ Source code
# File activerecord/lib/active_record/connection_handling.rb, line 241
    def while_preventing_writes(enabled = true, &block)
      if legacy_connection_handling
        connection_handler.while_preventing_writes(enabled, &block)
      else
        connected_to(role: current_role, prevent_writes: enabled, &block)
      end
    end
πŸ”Ž See on GitHub