aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
authorschneems <richard.schneeman@gmail.com>2014-01-01 17:33:59 -0500
committerschneems <richard.schneeman@gmail.com>2014-01-09 16:35:37 -0600
commit6cc03675d30b58e28f585720dad14e947a57ff5b (patch)
treee960f21e39f90152903eb0109bcc9ed54b8210cb /railties
parent4c32b729517a9a94e3d2a43f76df864fc5fc6e77 (diff)
downloadrails-6cc03675d30b58e28f585720dad14e947a57ff5b.tar.gz
rails-6cc03675d30b58e28f585720dad14e947a57ff5b.tar.bz2
rails-6cc03675d30b58e28f585720dad14e947a57ff5b.zip
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:<tasks>` - ActiveRecord.establish_connection - With Rails - `rake db:<tasks>` - `rails <server> | <console>` - `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.
Diffstat (limited to 'railties')
-rw-r--r--railties/lib/rails/application/configuration.rb16
-rw-r--r--railties/lib/rails/commands/dbconsole.rb15
-rw-r--r--railties/test/commands/dbconsole_test.rb2
3 files changed, 23 insertions, 10 deletions
diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb
index 9975bb8596..e902205a13 100644
--- a/railties/lib/rails/application/configuration.rb
+++ b/railties/lib/rails/application/configuration.rb
@@ -88,17 +88,23 @@ module Rails
end
end
- # Loads and returns the configuration of the database.
+ # Loads and returns the entire raw configuration of database from
+ # values stored in `config/database.yml`.
def database_configuration
- yaml = paths["config/database"].first
- if File.exist?(yaml)
+ yaml = Pathname.new(paths["config/database"].first || "")
+
+ config = if yaml.exist?
require "erb"
- YAML.load ERB.new(IO.read(yaml)).result
+ YAML.load(ERB.new(yaml.read).result) || {}
elsif ENV['DATABASE_URL']
- nil
+ # Value from ENV['DATABASE_URL'] is set to default database connection
+ # by Active Record.
+ {}
else
raise "Could not load database configuration. No such file - #{yaml}"
end
+
+ config
rescue Psych::SyntaxError => e
raise "YAML syntax error occurred while parsing #{paths["config/database"].first}. " \
"Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
diff --git a/railties/lib/rails/commands/dbconsole.rb b/railties/lib/rails/commands/dbconsole.rb
index c265ed8f36..f6d8aec30d 100644
--- a/railties/lib/rails/commands/dbconsole.rb
+++ b/railties/lib/rails/commands/dbconsole.rb
@@ -81,10 +81,11 @@ module Rails
def config
@config ||= begin
- require APP_PATH
- ActiveRecord::ConnectionAdapters::ConnectionSpecification::Resolver.new(
- Rails.application.config.database_configuration || {}
- ).resolve(ENV["DATABASE_URL"])
+ if configurations[environment].blank?
+ raise ActiveRecord::AdapterNotSpecified, "'#{environment}' database is not configured. Available configuration: #{configurations.inspect}"
+ else
+ configurations[environment]
+ end
end
end
@@ -98,6 +99,12 @@ module Rails
protected
+ def configurations
+ require APP_PATH
+ ActiveRecord::Base.configurations = Rails.application.config.database_configuration
+ ActiveRecord::Base.configurations
+ end
+
def parse_arguments(arguments)
options = {}
diff --git a/railties/test/commands/dbconsole_test.rb b/railties/test/commands/dbconsole_test.rb
index 7ad83a8b5d..24db395e6e 100644
--- a/railties/test/commands/dbconsole_test.rb
+++ b/railties/test/commands/dbconsole_test.rb
@@ -223,7 +223,7 @@ class Rails::DBConsoleTest < ActiveSupport::TestCase
private
def app_db_config(results)
- Rails.application.config.stubs(:database_configuration).returns(results)
+ Rails.application.config.stubs(:database_configuration).returns(results || {})
end
def dbconsole