connection_handling.rb 5.0 KB
Newer Older
1 2
module ActiveRecord
  module ConnectionHandling
3
    RAILS_ENV   = -> { (Rails.env if defined?(Rails.env)) || ENV["RAILS_ENV"] || ENV["RACK_ENV"] }
4 5
    DEFAULT_ENV = -> { RAILS_ENV.call || "default_env" }

6 7
    # Establishes the connection to the database. Accepts a hash as input where
    # the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
8
    # example for regular databases (MySQL, PostgreSQL, etc):
9 10
    #
    #   ActiveRecord::Base.establish_connection(
R
Ryuta Kamizono 已提交
11
    #     adapter:  "mysql2",
A
AvnerCohen 已提交
12 13 14 15
    #     host:     "localhost",
    #     username: "myuser",
    #     password: "mypass",
    #     database: "somedatabase"
16 17 18 19 20
    #   )
    #
    # Example for SQLite database:
    #
    #   ActiveRecord::Base.establish_connection(
J
Julian Simioni 已提交
21
    #     adapter:  "sqlite3",
22
    #     database: "path/to/dbfile"
23 24 25 26 27
    #   )
    #
    # Also accepts keys as strings (for parsing from YAML for example):
    #
    #   ActiveRecord::Base.establish_connection(
J
Julian Simioni 已提交
28
    #     "adapter"  => "sqlite3",
29
    #     "database" => "path/to/dbfile"
30 31 32 33 34 35 36 37
    #   )
    #
    # Or a URL:
    #
    #   ActiveRecord::Base.establish_connection(
    #     "postgres://myuser:mypass@localhost/somedatabase"
    #   )
    #
38 39
    # In case {ActiveRecord::Base.configurations}[rdoc-ref:Core.configurations]
    # is set (Rails automatically loads the contents of config/database.yml into it),
40 41 42 43 44
    # a symbol can also be given as argument, representing a key in the
    # configuration hash:
    #
    #   ActiveRecord::Base.establish_connection(:production)
    #
45
    # The exceptions AdapterNotSpecified, AdapterNotFound and +ArgumentError+
46
    # may be returned on an error.
47
    def establish_connection(config = nil)
J
Jon Moss 已提交
48
      raise "Anonymous class is not allowed." unless name
A
Arthur Neves 已提交
49

50 51 52
      config ||= DEFAULT_ENV.call.to_sym
      spec_name = self == Base ? "primary" : name
      self.connection_specification_name = spec_name
53 54 55 56 57 58

      resolver = ConnectionAdapters::ConnectionSpecification::Resolver.new(Base.configurations)
      spec = resolver.resolve(config).symbolize_keys
      spec[:name] = spec_name

      connection_handler.establish_connection(spec)
59 60
    end

61
    class MergeAndResolveDefaultUrlConfig # :nodoc:
62
      def initialize(raw_configurations)
63
        @raw_config = raw_configurations.dup
64
        @env = DEFAULT_ENV.call.to_s
65 66 67 68 69 70 71 72 73 74
      end

      # Returns fully resolved connection hashes.
      # Merges connection information from `ENV['DATABASE_URL']` if available.
      def resolve
        ConnectionAdapters::ConnectionSpecification::Resolver.new(config).resolve_all
      end

      private
        def config
75
          @raw_config.dup.tap do |cfg|
M
Matthew Draper 已提交
76
            if url = ENV['DATABASE_URL']
M
Matthew Draper 已提交
77 78
              cfg[@env] ||= {}
              cfg[@env]["url"] ||= url
79
            end
80 81 82 83
          end
        end
    end

84 85 86 87 88 89 90
    # 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.
    def connection
      retrieve_connection
    end

91
    attr_writer :connection_specification_name
A
Arthur Neves 已提交
92

J
Jon Moss 已提交
93
    # Return the specification name from the current class or its parent.
94
    def connection_specification_name
95
      if !defined?(@connection_specification_name) || @connection_specification_name.nil?
96
        return self == Base ? "primary" : superclass.connection_specification_name
A
Arthur Neves 已提交
97
      end
98
      @connection_specification_name
A
Arthur Neves 已提交
99 100
    end

101
    def connection_id
102
      ActiveRecord::RuntimeRegistry.connection_id ||= Thread.current.object_id
103 104 105
    end

    def connection_id=(connection_id)
106
      ActiveRecord::RuntimeRegistry.connection_id = connection_id
107 108 109 110 111
    end

    # Returns the configuration of the associated connection as a hash:
    #
    #  ActiveRecord::Base.connection_config
A
AvnerCohen 已提交
112
    #  # => {pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}
113 114 115 116 117 118 119
    #
    # Please use only for reading.
    def connection_config
      connection_pool.spec.config
    end

    def connection_pool
120
      connection_handler.retrieve_connection_pool(connection_specification_name) or raise ConnectionNotEstablished
121 122 123
    end

    def retrieve_connection
124
      connection_handler.retrieve_connection(connection_specification_name)
125 126
    end

127
    # Returns +true+ if Active Record is connected.
128
    def connected?
129
      connection_handler.connected?(connection_specification_name)
130 131
    end

132 133
    def remove_connection(name = nil)
      name ||= @connection_specification_name if defined?(@connection_specification_name)
134 135 136 137 138 139 140
      # if removing a connection that have a pool, we reset the
      # connection_specification_name so it will use the parent
      # pool.
      if connection_handler.retrieve_connection_pool(name)
        self.connection_specification_name = nil
      end

141
      connection_handler.remove_connection(name)
142 143
    end

J
Jon Leighton 已提交
144 145 146 147
    def clear_cache! # :nodoc:
      connection.schema_cache.clear!
    end

148
    delegate :clear_active_connections!, :clear_reloadable_connections!,
149
      :clear_all_connections!, :to => :connection_handler
150 151
  end
end