Skip to content

Commit

Permalink
Merge pull request #14633 from matthewd/narrow_database_url
Browse files Browse the repository at this point in the history
Only apply DATABASE_URL for Rails.env
  • Loading branch information
rafaelfranca committed Apr 8, 2014
1 parent cc15d99 commit 3a118cc
Show file tree
Hide file tree
Showing 14 changed files with 251 additions and 101 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class ConnectionUrlResolver # :nodoc:
def initialize(url) def initialize(url)
raise "Database URL cannot be empty" if url.blank? raise "Database URL cannot be empty" if url.blank?
@uri = URI.parse(url) @uri = URI.parse(url)
@adapter = @uri.scheme @adapter = @uri.scheme.gsub('-', '_')
@adapter = "postgresql" if @adapter == "postgres" @adapter = "postgresql" if @adapter == "postgres"


if @uri.opaque if @uri.opaque
Expand Down Expand Up @@ -234,10 +234,10 @@ def resolve_string_connection(spec)
# 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 # this ambiguous behaviour and in the future this function
# can be removed in favor of resolve_url_connection. # can be removed in favor of resolve_url_connection.
if configurations.key?(spec) if configurations.key?(spec) || spec !~ /:/
ActiveSupport::Deprecation.warn "Passing a string to ActiveRecord::Base.establish_connection " \ 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" "for a configuration lookup is deprecated, please pass a symbol (#{spec.to_sym.inspect}) instead"
resolve_connection(configurations[spec]) resolve_symbol_connection(spec)
else else
resolve_url_connection(spec) resolve_url_connection(spec)
end end
Expand Down
35 changes: 6 additions & 29 deletions activerecord/lib/active_record/connection_handling.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ def establish_connection(spec = nil)
end end


class MergeAndResolveDefaultUrlConfig # :nodoc: class MergeAndResolveDefaultUrlConfig # :nodoc:
def initialize(raw_configurations, url = ENV['DATABASE_URL']) def initialize(raw_configurations)
@raw_config = raw_configurations.dup @raw_config = raw_configurations.dup
@url = url @env = DEFAULT_ENV.call.to_s
end end


# Returns fully resolved connection hashes. # Returns fully resolved connection hashes.
Expand All @@ -71,33 +71,10 @@ def resolve


private private
def config def config
if @url @raw_config.dup.tap do |cfg|
raw_merged_into_default if url = ENV['DATABASE_URL']
else cfg[@env] ||= {}
@raw_config cfg[@env]["url"] ||= url
end
end

def raw_merged_into_default
default = default_url_hash

@raw_config.each do |env, values|
default[env] = values || {}
default[env].merge!("url" => @url) { |h, v1, v2| v1 || v2 } if default[env].is_a?(Hash)
end
default
end

# When the raw configuration is not present and ENV['DATABASE_URL']
# is available we return a hash with the connection information in
# the connection URL. This hash responds to any string key with
# resolved connection information.
def default_url_hash
Hash.new do |hash, key|
hash[key] = if key.is_a? String
ActiveRecord::ConnectionAdapters::ConnectionSpecification::ConnectionUrlResolver.new(@url).to_hash
else
nil
end end
end end
end end
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -25,35 +25,45 @@ def spec(spec, config)
ConnectionSpecification::Resolver.new(klass.new(config).resolve).spec(spec) ConnectionSpecification::Resolver.new(klass.new(config).resolve).spec(spec)
end end


def test_resolver_with_database_uri_and_known_key def test_resolver_with_database_uri_and_current_env_symbol_key
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo" } } config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
actual = resolve(:production, config) actual = resolve(:default_env, config)
expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" }
assert_equal expected, actual assert_equal expected, actual
end end


def test_resolver_with_database_uri_and_known_string_key def test_resolver_with_database_uri_and_and_current_env_string_key
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo" } } config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } }
actual = assert_deprecated { resolve("production", config) } actual = assert_deprecated { resolve("default_env", config) }
expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" }
assert_equal expected, actual assert_equal expected, actual
end end


def test_resolver_with_database_uri_and_unknown_symbol_key def test_resolver_with_database_uri_and_known_key
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } config = { "production" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } }
actual = resolve(:production, config) actual = resolve(:production, config)
expected = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } expected = { "adapter"=>"not_postgres", "database"=>"not_foo", "host"=>"localhost" }
assert_equal expected, actual assert_equal expected, actual
end end


def test_resolver_with_database_uri_and_unknown_string_key def test_resolver_with_database_uri_and_unknown_symbol_key
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
assert_raises AdapterNotSpecified do assert_raises AdapterNotSpecified do
spec("production", config) resolve(:production, config)
end
end

def test_resolver_with_database_uri_and_unknown_string_key
ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } }
assert_deprecated do
assert_raises AdapterNotSpecified do
spec("production", config)
end
end end
end end


Expand All @@ -73,16 +83,24 @@ def test_jdbc_url


def test_environment_does_not_exist_in_config_url_does_exist def test_environment_does_not_exist_in_config_url_does_exist
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"
config = { "not_production" => { "adapter" => "not_postgres", "database" => "not_foo" } } config = { "not_default_env" => { "adapter" => "not_postgres", "database" => "not_foo" } }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expect_prod = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" } expect_prod = { "adapter"=>"postgresql", "database"=>"foo", "host"=>"localhost" }
assert_equal expect_prod, actual["production"] assert_equal expect_prod, actual["default_env"]
end

def test_url_with_hyphenated_scheme
ENV['DATABASE_URL'] = "ibm-db://localhost/foo"
config = { "default_env" => { "adapter" => "not_postgres", "database" => "not_foo", "host" => "localhost" } }
actual = resolve(:default_env, config)
expected = { "adapter"=>"ibm_db", "database"=>"foo", "host"=>"localhost" }
assert_equal expected, actual
end end


def test_string_connection def test_string_connection
config = { "production" => "postgres://localhost/foo" } config = { "default_env" => "postgres://localhost/foo" }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expected = { "production" => expected = { "default_env" =>
{ "adapter" => "postgresql", { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost" "host" => "localhost"
Expand All @@ -92,9 +110,9 @@ def test_string_connection
end end


def test_url_sub_key def test_url_sub_key
config = { "production" => { "url" => "postgres://localhost/foo" } } config = { "default_env" => { "url" => "postgres://localhost/foo" } }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expected = { "production" => expected = { "default_env" =>
{ "adapter" => "postgresql", { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost" "host" => "localhost"
Expand Down Expand Up @@ -123,9 +141,10 @@ def test_blank_with_database_url
expected = { "adapter" => "postgresql", expected = { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost" } "host" => "localhost" }
assert_equal expected, actual["production"] assert_equal expected, actual["default_env"]
assert_equal expected, actual["development"] assert_equal nil, actual["production"]
assert_equal expected, actual["test"] assert_equal nil, actual["development"]
assert_equal nil, actual["test"]
assert_equal nil, actual[:production] assert_equal nil, actual[:production]
assert_equal nil, actual[:development] assert_equal nil, actual[:development]
assert_equal nil, actual[:test] assert_equal nil, actual[:test]
Expand All @@ -134,9 +153,9 @@ def test_blank_with_database_url
def test_url_sub_key_with_database_url def test_url_sub_key_with_database_url
ENV['DATABASE_URL'] = "NOT-POSTGRES://localhost/NOT_FOO" ENV['DATABASE_URL'] = "NOT-POSTGRES://localhost/NOT_FOO"


config = { "production" => { "url" => "postgres://localhost/foo" } } config = { "default_env" => { "url" => "postgres://localhost/foo" } }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expected = { "production" => expected = { "default_env" =>
{ "adapter" => "postgresql", { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost" "host" => "localhost"
Expand All @@ -148,9 +167,9 @@ def test_url_sub_key_with_database_url
def test_merge_no_conflicts_with_database_url def test_merge_no_conflicts_with_database_url
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"


config = {"production" => { "pool" => "5" } } config = {"default_env" => { "pool" => "5" } }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expected = { "production" => expected = { "default_env" =>
{ "adapter" => "postgresql", { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost", "host" => "localhost",
Expand All @@ -163,9 +182,9 @@ def test_merge_no_conflicts_with_database_url
def test_merge_conflicts_with_database_url def test_merge_conflicts_with_database_url
ENV['DATABASE_URL'] = "postgres://localhost/foo" ENV['DATABASE_URL'] = "postgres://localhost/foo"


config = {"production" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } } config = {"default_env" => { "adapter" => "NOT-POSTGRES", "database" => "NOT-FOO", "pool" => "5" } }
actual = klass.new(config).resolve actual = klass.new(config).resolve
expected = { "production" => expected = { "default_env" =>
{ "adapter" => "postgresql", { "adapter" => "postgresql",
"database" => "foo", "database" => "foo",
"host" => "localhost", "host" => "localhost",
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -23,7 +23,27 @@ test:
<<: *default <<: *default
database: <%= app_name %>_test database: <%= app_name %>_test


# Do not keep production credentials in the repository, # As with config/secrets.yml, you never want to store sensitive information,
# instead read the configuration from the environment. # like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="frontbase://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%%= ENV['DATABASE_URL'] %>
#
production: production:
url: <%%= ENV["DATABASE_URL"] %> <<: *default
database: <%= app_name %>_production
username: <%= app_name %>
password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %>
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -61,7 +61,27 @@ test:
<<: *default <<: *default
database: <%= app_name[0,4] %>_tst database: <%= app_name[0,4] %>_tst


# Do not keep production credentials in the repository, # As with config/secrets.yml, you never want to store sensitive information,
# instead read the configuration from the environment. # like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="ibm-db://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%%= ENV['DATABASE_URL'] %>
#
production: production:
url: <%%= ENV["DATABASE_URL"] %> <<: *default
database: <%= app_name %>_production
username: <%= app_name %>
password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %>
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@ test:
<<: *default <<: *default
url: jdbc:db://localhost/<%= app_name %>_test url: jdbc:db://localhost/<%= app_name %>_test


# Do not keep production credentials in the repository, # As with config/secrets.yml, you never want to store sensitive information,
# instead read the configuration from the environment. # like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
production: production:
url: <%%= ENV["DATABASE_URL"] %> url: jdbc:db://localhost/<%= app_name %>_production
username: <%= app_name %>
password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %>
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -26,6 +26,27 @@ test:
<<: *default <<: *default
database: <%= app_name %>_test database: <%= app_name %>_test


# Do not keep production credentials in the repository, # As with config/secrets.yml, you never want to store sensitive information,
# instead read the configuration from the environment. # like your database password, in your source code. If your source code is
production: <%%= ENV["DATABASE_URL"] %> # ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="mysql://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%%= ENV['DATABASE_URL'] %>
#
production:
<<: *default
database: <%= app_name %>_production
username: <%= app_name %>
password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %>
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -42,7 +42,27 @@ test:
<<: *default <<: *default
database: <%= app_name %>_test database: <%= app_name %>_test


# Do not keep production credentials in the repository, # As with config/secrets.yml, you never want to store sensitive information,
# instead read the configuration from the environment. # like your database password, in your source code. If your source code is
# ever seen by anyone, they now have access to your database.
#
# Instead, provide the password as a unix environment variable when you boot
# the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full rundown on how to provide these environment variables in a
# production deployment.
#
# On Heroku and other platform providers, you may have a full connection URL
# available as an environment variable. For example:
#
# DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
# production:
# url: <%%= ENV['DATABASE_URL'] %>
#
production: production:
url: <%%= ENV["DATABASE_URL"] %> <<: *default
database: <%= app_name %>_production
username: <%= app_name %>
password: <%%= ENV['<%= app_name.upcase %>_DATABASE_PASSWORD'] %>
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ test:
<<: *default <<: *default
database: db/test.sqlite3 database: db/test.sqlite3


# Do not keep production credentials in the repository,
# instead read the configuration from the environment.
production: production:
url: <%%= ENV["DATABASE_URL"] %> <<: *default
database: db/production.sqlite3
Loading

0 comments on commit 3a118cc

Please sign in to comment.