rails/rails — Issue #5297: Database connection parameters are tied to the filesystem
Author: dbalatero
Created: 2012-03-06 01:26:23+00:00
State: open

Hey all,

I've ran into a pretty large headache with configuring my database today, and as a result, I'd like to argue for *completely decoupling database configuration from the file system*, if so desired by the user. I'm more looking for debate/interest from Rails core / other users on this issue at this point, not commitment from anyone in particular to write code.

**My scenario**

Bugs with ActiveRecord prepared statements were taking down my servers in production, so I wanted to disable them. To do this in Rails 3.1.4, you have to set:

```yaml
production:
prepared_statements: false
```

inside of `config/database.yml`.

My problem was that I didn't have access to this `.yml` file, as I run my app on top of Heroku Bamboo stack, which doesn't seem to let you inject arbitrary config parameters into your database.yml.

Unfortunately, `railties/lib/rails/application/configuration.rb` defines this method as the single accessor for the database configuration:

```ruby
def database_configuration
require 'erb'
# no way to override this!
YAML::load(ERB.new(IO.read(paths["config/database"].first)).result)
end
```

In order to save my production app, I had to add the following unstable patch to `lib/patches` and require it right after `require 'rails/all'` in my `config/application.rb` file:

```ruby
require 'rails/application/configuration'

module Rails
class Application
class Configuration < ::Rails::Engine::Configuration
alias :__old_database_configuration__ :database_configuration

def database_configuration
with_disabled_prepared_statements(__old_database_configuration__)
end

private

# This forces all connections (development, test, production, etc)
# to turn off prepared statements at the config level.
def with_disabled_prepared_statements(config)
config.keys.each do |key|
config[key]['prepared_statements'] ||= false
end
config
end
end
end
end
```

This is obviously not ideal – especially given how uncertain Rails upgrades can be already without monkey patches sitting around in your app :)

**A possible simple fix**

Instead of hard-coding the `database_configuration` method to the code above ^^, make it configurable. By default, it would use the YAML/ERB/file method above. However, you could override it with a block:

```ruby
Rails.configuration.database_configuration = lambda do
read_from_our_secure_configuration_server()
end
```

Or perhaps via a plain class:

```ruby
class SecureConfigReader
def database_configuration
read_from_our_secure_configuration_server()
end
end

Rails.configuration.database_configuration = SecureConfigReader.new
```

Any other ideas on how to achieve more control over database configuration would be welcome as well – this is just what seems most natural to me.

**Another scenario in which more control would be useful**

I would like to centralize my security-sensitive application configuration (private keys, database passwords) inside of Chef data bags, which my production machines would then read from over secure HTTPS on config initialization.

I currently would have to keep using the `config/database.yml` filesystem interface + Chef data bags to manage my database configuration. I'd much rather contain this all in one place inside of my app, instead.

*sidenote*: This was previously raised as an issue in 2008, but never gained any traction: http://www.mail-archive.com/rubyonrails-core@googlegroups.com/msg06694.html