From fbb79b517f3127ba620fedd01849f9628b78d6ce Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 20 Dec 2013 16:13:34 -0800 Subject: fix url connections for sqlite3 --- .../connection_adapters/connection_specification.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 64fc9e95d8..66d7f04fc3 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -69,11 +69,22 @@ module ActiveRecord config = URI.parse url adapter = config.scheme adapter = "postgresql" if adapter == "postgres" + + database = if adapter == 'sqlite3' + if '/:memory:' == config.path + ':memory:' + else + config.path + end + else + config.path.sub(%r{^/},"") + end + spec = { :adapter => adapter, :username => config.user, :password => config.password, :port => config.port, - :database => config.path.sub(%r{^/},""), + :database => database, :host => config.host } spec.reject!{ |_,value| value.blank? } -- cgit v1.2.3 From c390e60811b2e11bfd5d79b15bfb43690c1a1339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 23 Dec 2013 20:15:52 +0100 Subject: Guarantee the connection resolver handles string values This commit also cleans up the rake tasks that were checking for DATABASE_URL in different places. In fact, it would be nice to deprecate DATABASE_URL usage in the long term, considering the direction we are moving of allowing those in .yml files. --- .../connection_specification.rb | 49 +++++++++++++--------- 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 66d7f04fc3..a87eed5243 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -16,34 +16,43 @@ module ActiveRecord ## # Builds a ConnectionSpecification from user input class Resolver # :nodoc: - attr_reader :config, :klass, :configurations + attr_reader :configurations - def initialize(config, configurations) - @config = config + def initialize(configurations) @configurations = configurations end - def spec - case config - when nil - raise AdapterNotSpecified unless defined?(Rails.env) - resolve_string_connection Rails.env - when Symbol, String - resolve_string_connection config.to_s - when Hash - resolve_hash_connection config + def resolve(config) + if config + resolve_connection config + elsif defined?(Rails.env) + resolve_env_connection Rails.env + else + raise AdapterNotSpecified end end private - def resolve_string_connection(spec) # :nodoc: - hash = configurations.fetch(spec) do |k| - connection_url_to_hash(k) - end - raise(AdapterNotSpecified, "#{spec} database is not configured") unless hash + def resolve_connection(spec) #:nodoc: + case spec + when Symbol, String + resolve_env_connection spec.to_s + when Hash + resolve_hash_connection spec + end + end - resolve_hash_connection hash + def resolve_env_connection(spec) # :nodoc: + # Rails has historically accepted a string to mean either + # an environment key or a url spec. So we support both for + # now but it would be nice to limit the environment key only + # for symbols. + spec = configurations.fetch(spec.to_s) do + resolve_string_connection(spec) if spec.is_a?(String) + end + raise(AdapterNotSpecified, "#{spec} database is not configured") unless spec + resolve_connection spec end def resolve_hash_connection(spec) # :nodoc: @@ -65,8 +74,8 @@ module ActiveRecord ConnectionSpecification.new(spec, adapter_method) end - def connection_url_to_hash(url) # :nodoc: - config = URI.parse url + def resolve_string_connection(spec) # :nodoc: + config = URI.parse spec adapter = config.scheme adapter = "postgresql" if adapter == "postgres" -- cgit v1.2.3 From d8336cab32d0d8e8c2877cac26111cbecb5ac872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 24 Dec 2013 09:26:34 +0100 Subject: Fix build failures related to the new ENV options in yml --- .../active_record/connection_adapters/connection_specification.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index a87eed5243..5f50ca6aae 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -48,11 +48,11 @@ module ActiveRecord # an environment key or a url spec. So we support both for # now but it would be nice to limit the environment key only # for symbols. - spec = configurations.fetch(spec.to_s) do + config = configurations.fetch(spec.to_s) do resolve_string_connection(spec) if spec.is_a?(String) end - raise(AdapterNotSpecified, "#{spec} database is not configured") unless spec - resolve_connection spec + raise(AdapterNotSpecified, "#{spec} database is not configured") unless config + resolve_connection config end def resolve_hash_connection(spec) # :nodoc: -- cgit v1.2.3 From d2ed433b0af948da78e971bf342c506b27f6072f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 24 Dec 2013 10:02:07 +0100 Subject: Only build a ConnectionSpecification if required --- .../connection_specification.rb | 54 +++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 5f50ca6aae..a3c645c53c 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -32,6 +32,24 @@ module ActiveRecord end end + def spec(config) + spec = resolve(config).symbolize_keys + + raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter) + + path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter" + begin + require path_to_adapter + rescue Gem::LoadError => e + raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)." + rescue LoadError => e + raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace + end + + adapter_method = "#{spec[:adapter]}_connection" + ConnectionSpecification.new(spec, adapter_method) + end + private def resolve_connection(spec) #:nodoc: @@ -52,30 +70,15 @@ module ActiveRecord resolve_string_connection(spec) if spec.is_a?(String) end raise(AdapterNotSpecified, "#{spec} database is not configured") unless config - resolve_connection config + resolve_connection(config) end def resolve_hash_connection(spec) # :nodoc: - spec = spec.symbolize_keys - - raise(AdapterNotSpecified, "database configuration does not specify adapter") unless spec.key?(:adapter) - - path_to_adapter = "active_record/connection_adapters/#{spec[:adapter]}_adapter" - begin - require path_to_adapter - rescue Gem::LoadError => e - raise Gem::LoadError, "Specified '#{spec[:adapter]}' for database adapter, but the gem is not loaded. Add `gem '#{e.name}'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord)." - rescue LoadError => e - raise LoadError, "Could not load '#{path_to_adapter}'. Make sure that the adapter in config/database.yml is valid. If you use an adapter other than 'mysql', 'mysql2', 'postgresql' or 'sqlite3' add the necessary adapter gem to the Gemfile.", e.backtrace - end - - adapter_method = "#{spec[:adapter]}_connection" - - ConnectionSpecification.new(spec, adapter_method) + spec end def resolve_string_connection(spec) # :nodoc: - config = URI.parse spec + config = URI.parse spec adapter = config.scheme adapter = "postgresql" if adapter == "postgres" @@ -89,12 +92,12 @@ module ActiveRecord config.path.sub(%r{^/},"") end - spec = { :adapter => adapter, - :username => config.user, - :password => config.password, - :port => config.port, - :database => database, - :host => config.host } + spec = { "adapter" => adapter, + "username" => config.user, + "password" => config.password, + "port" => config.port, + "database" => database, + "host" => config.host } spec.reject!{ |_,value| value.blank? } @@ -103,8 +106,7 @@ module ActiveRecord spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) } if config.query - options = Hash[config.query.split("&").map{ |pair| pair.split("=") }].symbolize_keys - + options = Hash[config.query.split("&").map{ |pair| pair.split("=") }] spec.merge!(options) end -- cgit v1.2.3 From ec11807368318845a2542e8f5f51f3f5280135f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 24 Dec 2013 10:18:54 +0100 Subject: Deprecate use of string in establish_connection as connection lookup --- .../connection_specification.rb | 25 ++++++++++++++-------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index a3c645c53c..7e16156408 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -26,7 +26,7 @@ module ActiveRecord if config resolve_connection config elsif defined?(Rails.env) - resolve_env_connection Rails.env + resolve_env_connection Rails.env.to_sym else raise AdapterNotSpecified end @@ -55,7 +55,7 @@ module ActiveRecord def resolve_connection(spec) #:nodoc: case spec when Symbol, String - resolve_env_connection spec.to_s + resolve_env_connection spec when Hash resolve_hash_connection spec end @@ -63,14 +63,21 @@ module ActiveRecord def resolve_env_connection(spec) # :nodoc: # Rails has historically accepted a string to mean either - # an environment key or a url spec. So we support both for - # now but it would be nice to limit the environment key only - # for symbols. - config = configurations.fetch(spec.to_s) do - resolve_string_connection(spec) if spec.is_a?(String) + # an environment key or a url spec, so we have deprecated + # this ambiguous behaviour and in the future this function + # can be removed in favor of resolve_string_connection and + # resolve_symbol_connection. + if config = configurations[spec.to_s] + if spec.is_a?(String) + ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \ + "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead" + end + resolve_connection(config) + elsif spec.is_a?(String) + resolve_string_connection(spec) + else + raise(AdapterNotSpecified, "#{spec} database is not configured") end - raise(AdapterNotSpecified, "#{spec} database is not configured") unless config - resolve_connection(config) end def resolve_hash_connection(spec) # :nodoc: -- cgit v1.2.3 From 137c0e573b9fe03245d4dd2e2093da12ba732598 Mon Sep 17 00:00:00 2001 From: schneems Date: Sun, 29 Dec 2013 18:56:32 -0500 Subject: Extract db url connection logic to class --- .../connection_specification.rb | 113 ++++++++++++++------- 1 file changed, 79 insertions(+), 34 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 7e16156408..a1664509df 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -13,6 +13,83 @@ module ActiveRecord @config = original.config.dup end + # Expands a connection string into a hash + class ConnectionUrlResolver # :nodoc: + + # == Example + # url = 'postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000' + # ConnectionUrlResolver.new(url).to_hash + # # => { + # "adapter" => "postgresql", + # "host" => "localhost", + # "port" => 9000, + # "database" => "foo_test", + # "username" => "foo", + # "password" => "bar", + # "pool" => "5", + # "timeout" => "3000" + # } + def initialize(url) + raise "Database URL cannot be empty" if url.blank? + @uri = URI.parse(url) + @adapter = @uri.scheme + @adapter = "postgresql" if @adapter == "postgres" + @query = @uri.query || '' + end + + # Converts the given url to a full connection hash + def to_hash + config = raw_config.reject { |_,value| value.blank? } + config.map { |key,value| config[key] = uri_parser.unescape(value) if value.is_a? String } + config + end + + private + + def uri + @uri + end + + def uri_parser + @uri_parser ||= URI::Parser.new + end + + # Converts the query parameters of the uri into a hash + # "localhost?pool=5&reap_frequency=2" + # # => {"pool" => "5", "reap_frequency" => "2"} + # + # returns empty hash if no query present + # "localhost" + # # => {} + def query_hash + Hash[@query.split("&").map { |pair| pair.split("=") }] + end + + def raw_config + query_hash.merge({ + "adapter" => @adapter, + "username" => uri.user, + "password" => uri.password, + "port" => uri.port, + "database" => database, + "host" => uri.host }) + end + + # Returns name of the database + # sqlite3 expects this to be a full path or `:memory` + def database + if @adapter == 'sqlite3' + if '/:memory:' == uri.path + ':memory:' + else + uri.path + end + else + uri.path.sub(%r{^/},"") + end + end + end + ## # Builds a ConnectionSpecification from user input class Resolver # :nodoc: @@ -84,40 +161,8 @@ module ActiveRecord spec end - def resolve_string_connection(spec) # :nodoc: - config = URI.parse spec - adapter = config.scheme - adapter = "postgresql" if adapter == "postgres" - - database = if adapter == 'sqlite3' - if '/:memory:' == config.path - ':memory:' - else - config.path - end - else - config.path.sub(%r{^/},"") - end - - spec = { "adapter" => adapter, - "username" => config.user, - "password" => config.password, - "port" => config.port, - "database" => database, - "host" => config.host } - - spec.reject!{ |_,value| value.blank? } - - uri_parser = URI::Parser.new - - spec.map { |key,value| spec[key] = uri_parser.unescape(value) if value.is_a?(String) } - - if config.query - options = Hash[config.query.split("&").map{ |pair| pair.split("=") }] - spec.merge!(options) - end - - spec + def resolve_string_connection(url) # :nodoc: + ConnectionUrlResolver.new(url).to_hash end end end -- cgit v1.2.3 From 8c82ee838ec10fcfde45f99129c4376f8435dd06 Mon Sep 17 00:00:00 2001 From: schneems Date: Sun, 29 Dec 2013 21:57:55 -0500 Subject: [ci skip] ConnectionSpecification::Resolver Docs Document the internal interfaces of `ConnectionSpecification::Resolver` Change method name from `config` to `env` to better match the most common use case. --- .../connection_specification.rb | 94 ++++++++++++++++++---- 1 file changed, 80 insertions(+), 14 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index a1664509df..bea9a22442 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -13,11 +13,12 @@ module ActiveRecord @config = original.config.dup end - # Expands a connection string into a hash + # Expands a connection string into a hash. class ConnectionUrlResolver # :nodoc: # == Example - # url = 'postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000' + # + # url = "postgresql://foo:bar@localhost:9000/foo_test?pool=5&timeout=3000" # ConnectionUrlResolver.new(url).to_hash # # => { # "adapter" => "postgresql", @@ -37,7 +38,7 @@ module ActiveRecord @query = @uri.query || '' end - # Converts the given url to a full connection hash + # Converts the given URL to a full connection hash. def to_hash config = raw_config.reject { |_,value| value.blank? } config.map { |key,value| config[key] = uri_parser.unescape(value) if value.is_a? String } @@ -54,11 +55,13 @@ module ActiveRecord @uri_parser ||= URI::Parser.new end - # Converts the query parameters of the uri into a hash + # Converts the query parameters of the URI into a hash. + # # "localhost?pool=5&reap_frequency=2" - # # => {"pool" => "5", "reap_frequency" => "2"} + # # => { "pool" => "5", "reap_frequency" => "2" } + # + # returns empty hash if no query present. # - # returns empty hash if no query present # "localhost" # # => {} def query_hash @@ -75,8 +78,8 @@ module ActiveRecord "host" => uri.host }) end - # Returns name of the database - # sqlite3 expects this to be a full path or `:memory` + # Returns name of the database. + # Sqlite3 expects this to be a full path or `:memory`. def database if @adapter == 'sqlite3' if '/:memory:' == uri.path @@ -91,14 +94,32 @@ module ActiveRecord end ## - # Builds a ConnectionSpecification from user input + # Builds a ConnectionSpecification from user input. class Resolver # :nodoc: attr_reader :configurations + # Accepts a hash two layers deep, keys on the first layer represent + # environments such as "production". Keys must be strings. def initialize(configurations) @configurations = configurations end + # Returns a hash with database connection information. + # + # == Examples + # + # Full hash Configuration. + # + # configurations = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } } + # Resolver.new(configurations).resolve(:production) + # # => {host: "localhost", database: "foo", adapter: "sqlite3"} + # + # Initialized with URL configuration strings. + # + # configurations = { "production" => "postgresql://localhost/foo" } + # Resolver.new(configurations).resolve(:production) + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # def resolve(config) if config resolve_connection config @@ -109,6 +130,18 @@ module ActiveRecord end end + # Returns an instance of ConnectionSpecification for a given adapter. + # Accepts a hash one layer deep that contains all connection information. + # + # == Example + # + # config = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } } + # spec = Resolver.new(config).spec(:production) + # spec.adapter_method + # # => "sqlite3" + # spec.config + # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } + # def spec(config) spec = resolve(config).symbolize_keys @@ -129,7 +162,27 @@ module ActiveRecord private - def resolve_connection(spec) #:nodoc: + # Returns fully resolved connection, accepts hash, string or symbol. + # Always returns a hash. + # + # == Examples + # + # Symbol representing current environment. + # + # Resolver.new("production" => {}).resolve_connection(:production) + # # => {} + # + # One layer deep hash of connection values. + # + # Resolver.new({}).resolve_connection("adapter" => "sqlite3") + # # => { "adapter" => "sqlite3" } + # + # Connection URL. + # + # Resolver.new({}).resolve_connection("postgresql://localhost/foo") + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # + def resolve_connection(spec) case spec when Symbol, String resolve_env_connection spec @@ -138,9 +191,22 @@ module ActiveRecord end end - def resolve_env_connection(spec) # :nodoc: + # Takes the environment such as `:production` or `:development`. + # This requires that the @configurations was initialized with a key that + # matches. + # + # + # Resolver.new("production" => {}).resolve_env_connection(:production) + # # => {} + # + # Takes a connection URL. + # + # Resolver.new({}).resolve_env_connection("postgresql://localhost/foo") + # # => { "host" => "localhost", "database" => "foo", "adapter" => "postgresql" } + # + def resolve_env_connection(spec) # Rails has historically accepted a string to mean either - # an environment key or a url spec, so we have deprecated + # an environment key or a URL spec, so we have deprecated # this ambiguous behaviour and in the future this function # can be removed in favor of resolve_string_connection and # resolve_symbol_connection. @@ -157,11 +223,11 @@ module ActiveRecord end end - def resolve_hash_connection(spec) # :nodoc: + def resolve_hash_connection(spec) spec end - def resolve_string_connection(url) # :nodoc: + def resolve_string_connection(url) ConnectionUrlResolver.new(url).to_hash end end -- cgit v1.2.3 From 5b96027ef6ac6e507ec9caf9973069345ce6a7cd Mon Sep 17 00:00:00 2001 From: schneems Date: Mon, 30 Dec 2013 11:26:28 -0500 Subject: Allow "url" sub key in database.yml configuration Currently a developer can pass in a YAML configuration that fully specifies connection information: ``` production: database: triage_production adapter: password pool: 5 ``` They can also pass in a string that specifies a connection URL directly to an environment key: ``` production: postgresql://localhost/foo ``` This PR allows the use of both a connection url and specifying connection attributes via YAML through the use of the "url" sub key: ``` production: url: postgresql://localhost/foo pool: 3 ``` This will allow developers to inherit Active Record options such as `pool` from `&defaults` and still use a secure connection url such as `<%= ENV['DATABASE_URL'] %>`. The URL is expanded into a hash and then merged back into the YAML hash. If there are any conflicts, the values from the connection URL are preferred. Talked this over with @josevalim --- .../active_record/connection_adapters/connection_specification.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index bea9a22442..049768effc 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -223,7 +223,15 @@ module ActiveRecord end end + # Accepts a hash. Expands the "url" key that contains a + # URL database connection to a full connection + # hash and merges with the rest of the hash. + # Connection details inside of the "url" key win any merge conflicts def resolve_hash_connection(spec) + if url = spec.delete("url") + connection_hash = resolve_string_connection(url) + spec.merge!(connection_hash) + end spec end -- cgit v1.2.3 From 28161b7c884d4e780775657ad32f0f2b26294b2f Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 6 Jan 2014 09:07:44 -0200 Subject: Fix typo [ci skip] --- .../lib/active_record/connection_adapters/connection_specification.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 049768effc..b316107e37 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -79,7 +79,7 @@ module ActiveRecord end # Returns name of the database. - # Sqlite3 expects this to be a full path or `:memory`. + # Sqlite3 expects this to be a full path or `:memory:`. def database if @adapter == 'sqlite3' if '/:memory:' == uri.path -- cgit v1.2.3 From 5d238ea926560ad0cb1287c6bcc34d2d3d7f982d Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Mon, 6 Jan 2014 09:15:11 -0200 Subject: Fix AR connection resolver docs to return a hash with string keys [ci skip] --- .../lib/active_record/connection_adapters/connection_specification.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index b316107e37..9f210c5f33 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -112,7 +112,7 @@ module ActiveRecord # # configurations = { "production" => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3" } } # Resolver.new(configurations).resolve(:production) - # # => {host: "localhost", database: "foo", adapter: "sqlite3"} + # # => { "host" => "localhost", "database" => "foo", "adapter" => "sqlite3"} # # Initialized with URL configuration strings. # -- cgit v1.2.3 From 6cc03675d30b58e28f585720dad14e947a57ff5b Mon Sep 17 00:00:00 2001 From: schneems Date: Wed, 1 Jan 2014 17:33:59 -0500 Subject: Ensure Active Record connection consistency Currently Active Record can be configured via the environment variable `DATABASE_URL` or by manually injecting a hash of values which is what Rails does, reading in `database.yml` and setting Active Record appropriately. Active Record expects to be able to use `DATABASE_URL` without the use of Rails, and we cannot rip out this functionality without deprecating. This presents a problem though when both config is set, and a `DATABASE_URL` is present. Currently the `DATABASE_URL` should "win" and none of the values in `database.yml` are used. This is somewhat unexpected to me if I were to set values such as `pool` in the `production:` group of `database.yml` they are ignored. There are many ways that active record initiates a connection today: - Stand Alone (without rails) - `rake db:` - ActiveRecord.establish_connection - With Rails - `rake db:` - `rails | ` - `rails dbconsole` We should make all of these behave exactly the same way. The best way to do this is to put all of this logic in one place so it is guaranteed to be used. Here is my prosed matrix of how this behavior should work: ``` No database.yml No DATABASE_URL => Error ``` ``` database.yml present No DATABASE_URL => Use database.yml configuration ``` ``` No database.yml DATABASE_URL present => use DATABASE_URL configuration ``` ``` database.yml present DATABASE_URL present => Merged into `url` sub key. If both specify `url` sub key, the `database.yml` `url` sub key "wins". If other paramaters `adapter` or `database` are specified in YAML, they are discarded as the `url` sub key "wins". ``` ### Implementation Current implementation uses `ActiveRecord::Base.configurations` to resolve and merge all connection information before returning. This is achieved through a utility class: `ActiveRecord::ConnectionHandling::MergeAndResolveDefaultUrlConfig`. To understand the exact behavior of this class, it is best to review the behavior in activerecord/test/cases/connection_adapters/connection_handler_test.rb though it should match the above proposal. --- .../connection_adapters/connection_specification.rb | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'activerecord/lib/active_record/connection_adapters/connection_specification.rb') diff --git a/activerecord/lib/active_record/connection_adapters/connection_specification.rb b/activerecord/lib/active_record/connection_adapters/connection_specification.rb index 9f210c5f33..3f8b14bf67 100644 --- a/activerecord/lib/active_record/connection_adapters/connection_specification.rb +++ b/activerecord/lib/active_record/connection_adapters/connection_specification.rb @@ -123,13 +123,22 @@ module ActiveRecord def resolve(config) if config resolve_connection config - elsif defined?(Rails.env) - resolve_env_connection Rails.env.to_sym + elsif env = ActiveRecord::ConnectionHandling::RAILS_ENV.call + resolve_env_connection env.to_sym else raise AdapterNotSpecified end end + # Expands each key in @configurations hash into fully resolved hash + def resolve_all + config = configurations.dup + config.each do |key, value| + config[key] = resolve(value) if value + end + config + end + # Returns an instance of ConnectionSpecification for a given adapter. # Accepts a hash one layer deep that contains all connection information. # @@ -219,7 +228,7 @@ module ActiveRecord elsif spec.is_a?(String) resolve_string_connection(spec) else - raise(AdapterNotSpecified, "#{spec} database is not configured") + raise(AdapterNotSpecified, "'#{spec}' database is not configured. Available configuration: #{configurations.inspect}") end end -- cgit v1.2.3