Out with database.yml

Why was yaml used in the first place?

Something like this is ugly, but does the job:

config.active_record.connection.configure do |db|
   YAML.load(ERB.new(File.read('config/database.yml').result))[Rails.env].each_pair do |key, value|
     db.send("#{key}=", value)
   end
end

So, I hope Rails still natively supports the old YAML format after
this patch, to support old tutorials, and to provide a standardized
option when it is needed, such as Rails parsing geminstaller.yml if it
exists, or a hosting company parsing geminstaller.yml or database.yml
to auto-configure whatever...

To clarify, my patch tries to load database.yml if you don't set anything in your environment.

Also, I still don't think either option is DRY-er than the other,
because YAML supports reuse, as was just pointed out.

I was perhaps overzealous in declaring Ruby DRYer than YAML. That said, I think more people know how to DRY up Ruby than YAML. :wink:

Totally off topic at this point, sorry, but anyway...

John and I hacked on this a bit this morning. The conclusion is that
there is no reason to do what he said above. GemInstaller.autogem
already does everything you want if you desire to manage your gems
from YAML. See:

http://geminstaller.rubyforge.org/faq.html#rails_config_gems
http://geminstaller.rubyforge.org/documentation/tutorials.html#integrating_geminstaller_into_ruby_on_rails

Thanks!
-- Chad

I don't really mind dropping the YAML configuration, but is there any
reason you aren't just using a regular Hash? i.e.

  ## environment.rb

  config.active_record.connection = {
    :adapter => 'mysql',
    ....
  }

  ## environments/development.rb

  config.active_record.connection.merge {
    :database => 'my_app_dev',
    :username => 'dev',
    :password => 'password'
  }

(note the merge in specific environments)

I guess this boils down to - why generate the Hash, when just writing
the Hash is pretty much equally readable? Do we get some benefit using
the block/DSL-style syntax? If not, the implementation could perhaps
be simpler.

Running it through a proxy makes it easier to yell at the user when they try to set username/password in production. Also, credentials is handled differently from the other attributes. One could do all that with a Hash, but why apply behavior to data when you can bundle the data with the behavior?

Why was yaml used in the first place?

Because I thought dammit, we gotta use YAML for something -- aka not a
good reason at all :wink:

Reading the database configuration in for use in the db:console will
now require loading the entire framework! Sweet!

I have to chime in here and plead for you to leave the database.yml alone. Or if you must use ruby config, please leave the db.yml working. If the credentials/config is only in ruby and in the local variable format you showed earlier, then other tools from other languages are going to not be able to read this stuff in easily. Heck in that format even ruby cannot read the credentials in without loading rails and using eval hackery to make the local variables available outside of the file they are in.

  I see significant downsides to the pure ruby config:

1. cannot read from non ruby languages.
2. now we have to load the entire rails environment just to get all the db config, this adds needless overhead to what is currently an easy task
3. ruby config spread out over multiple environment files as well as a credential file is going to hamper server automation in a serious way.
4. there are countless daemons and plugins that read the database.yml to get the db config info. how will these daemons now get said info without loading all of the rails environment?

  I thought rails was all about not breaking backwards compatibility unless there is a very good reason? What is the very good reason to make deployment more difficult? What does this gain us must be weighed against what we lose with the ruby config.

-1

Thanks

- Ezra Zygmuntowicz
-- Founder & Software Architect
-- ezra@engineyard.com
-- EngineYard.com

  I have to chime in here and plead for you to leave the database.yml
alone. Or if you must use ruby config, please leave the db.yml
working. If the credentials/config is only in ruby and in the local
variable format you showed earlier, then other tools from other
languages are going to not be able to read this stuff in easily. Heck
in that format even ruby cannot read the credentials in without
loading rails and using eval hackery to make the local variables
available outside of the file they are in.

*The patch leaves database.yml alone.* If no database configuration is done in the environment, Rails still looks in database.yml.

  I see significant downsides to the pure ruby config:

It seems there are a lot of deployment-time concerns here. Would it help if there was a Rake task to dump database.yml for a given environment?

I thought rails was all about not breaking backwards compatibility
unless there is a very good reason? What is the very good reason to
make deployment more difficult? What does this gain us must be weighed
against what we lose with the ruby config.

What part of deploying a typical Rails app is made more difficult? If anything, I'd think the external credential file makes things easier than it was before.

I am also skeptical about this switch. It works as is, and supporting
both methods will just confuse people. Ezra's point about formatting
is also a good point. Most other languages have a yaml parsing
library, but if they have to parse a ruby config, it's not really an
elegant solution. If we are going to do this for sure, I'd say a rake
task is essential, but even then I think the yaml file alone is
perfect for what it does.

-1

  I see significant downsides to the pure ruby config:

It seems there are a lot of deployment-time concerns here. Would it

help if there was a Rake task to dump database.yml for a given
environment?

The assumption here is that all servers in a given environment are configured with the same db credentials. That’s usually but not always true.

The database.yml file is a pure configuration file and it covers a very specific domain. It doesn’t make sense to me that it would be rubified just to be consistent with the rest of the initialization process.

Has anyone actually needed this ruby database configuration functionality?

-1

::Jack Danger

Duncan Beevers wrote:

Reading the database configuration in for use in the db:console will
now require loading the entire framework! Sweet!

I think Duncan has a good, albeit snarky, point. If we do switch to the ruby-based config we have to make sure that we dont slow other parts of the framework.

Ezra Zygmuntowicz wrote:

  I see significant downsides to the pure ruby config:

4. there are countless daemons and plugins that read the database.yml
to get the db config info. how will these daemons now get said info
without loading all of the rails environment?

   I thought rails was all about not breaking backwards compatibility
unless there is a very good reason? What is the very good reason to
make deployment more difficult? What does this gain us must be weighed
against what we lose with the ruby config.

-1

On further thought, I think we should just stay with the yaml file.

I have to give a -1 to the possiblity of using both the ruby and yaml methods. It isnt DRY.

I think DHH unintentionally did the right thing when he kept the db config out of ruby.

-1

If the database credentials reside in the ruby environment files then
we would be committing our database passwords into the repository.
Anyone with read access to the source code now has credentials to the
db. I'm skeptical of overly paranoid security measures, but this to me
this just seems blatantly a bad practice.

This ALMOST sounds like a good idea, but this really would be non-DRY,
in a dangerous way. Is the database.yml I dumped (or someone else
dumped) up-to-date? How do I know? When do I re-dump? Who re-dumps?

There's no reason to keep the database credentials in environment.rb.
Just throw them in a separate file, say database.rb, and ignore that
the way you currently do database.yml.

What's nice about this patch is that you can put the global configs in
environment.rb (UTF8, db host, database name) and leave just the
sensitive ones out of source control (username, password).

And, of course, many databases don't have any sensitive credentials to
worry about, like sqlite3.

    - Scott

Awesome - so I get to distribute the concept of database configuration
into multiple files. Best yet each rails project can come up with it's
own conventions on what it should call this file and what should go in
it.

Awesome - so I get to distribute the concept of database configuration
into multiple files.

You do currently. Is that a problem?

Best yet each rails project can come up with it's
own conventions on what it should call this file and what should go in
it.

Yep! Because each rails project best understands its own needs and
requirements.

I expect most Rails devs will continue to use database.yml the way
they currently do. There's no reason to break backward compatibility
but there's every reason to allow forward progress.

    - Scott

What's nice about this patch is that you can put the global configs in
environment.rb (UTF8, db host, database name) and leave just the
sensitive ones out of source control (username, password).
  
This argument has been given a few times. Am I the only one who considers the db host en database name to be just as security sensitive as the username and password? Why would I tell anyone that the safe is located behind the Van Gogh painting I've got hanging here?

Lawrence