Last Updated: March 02, 2016
· hopsoft

Use Rails 4 secrets.yml for database config

Don't spread your configuration across multiple files. Here's how to leverage secrets.yml for your database config too.

  • Rename config/secrets.yml to config/secrets.yml.example
  • Commit
  • cp config/secrets.yml.example config/secrets.yml
  • Update .gitignore to include config/secrets.yml
  • Add the a database section to config/secrets.yml Note the explicit use of symbols.

        :host: localhost
        :name: my_project_development
        :username: root
        :password: password
    # add database section to all envs...
  • Update config/database.yml to look like something like this.

    default: &default
      host: <%= Rails.application.secrets[:database][:host] %>
      adapter: postgresql
      encoding: UTF8
      database: <%= Rails.application.secrets[:database][:name] %>
      pool: 10
      reaping_frequency: 30
      username: <%= Rails.application.secrets[:database][:username] %>
      password: <%= Rails.application.secrets[:database][:password] %>
    development: *default
    test: *default
    production: *default

13 Responses
Add your response


But why ? We have database.yml for that propuse.

over 1 year ago ·

This is what I like using Dotenv for, configuration files reference environment variables then they can be configured on the server or a .env file.

over 1 year ago ·

I was just chatting on Twitter about this exact topic. What timing. The advantages of this are stubbing and working with a clear API. Having ENV variables spread throughout the codebase can be hard to reason with. I'd like it if it were possible to add validation rules though ala a Yaml-backed ActiveModel record to mitigate malicious or simply invalid ENV variables.

over 1 year ago ·

I wouldn't limit this to Database configuration though.

@dvito I think the advantage of this vs just modifying database.yml is single source of truth though.

over 1 year ago ·

Excellent work.

over 1 year ago ·

We use this technique for the simplicity of having a single source of truth for all app configuration that's easy to manage & reason about.

We deploy with our apps with Docker & use Chef to provision the metal.

  • The canonical source of secrets.yml lives in our Chef setup
  • Chef copies the secrets.yml file to all servers in the cluster
  • Docker containers mount the directory where secrets.yml is kept
  • On startup, the containers copy secrets.yml to APP/config/secrets.yml then start the app

It's working nicely for us & removes the cognitive load of having configs spread across multiple files & environment variables. YMMV

over 1 year ago ·

You can load all your ENV vars to the application in the same place: But I tend to agree with 12 factors in that things should be based on ENV vars so that you can deploy without worrying about config files. This also works really well from things like Docker.


over 1 year ago ·

Symfony2 uses something called Incenteev ParameterHandler which generates config (yml files) on the fly. I've ported it to ruby: https://github.com/khasinski/fillparams

You basically ship .dist (like .sample) files and during build it will ask for missing parameters. Useful for development (new developer doesn't have to guess where to look for config files and what else is there to configure). It copies missing parameters when you run it in non-interactive environment.

over 1 year ago ·

I ran into a lot of trouble getting this working in docker until I finally read all of the details around how nginx deals with environmental variables. In my scenario I could see all of my variables but when nginx started passenger, passenger would default to a local database and not see the environmental variables that I was passing.


over 1 year ago ·

You'll want to change out the secrets in secrets.yml unless you are ok with those going out to the interweb

over 1 year ago ·

how to use secret.yml to production mode if you add that in .gitignore?

over 1 year ago ·

Do you still use this approach? I'm trying it in Rails 4.2 and it seems like the secrets aren't available at the time the database.yml is parsed. I'm going to look into it some more but wanted to check in with you as well.

over 1 year ago ·

Whoops - that was my mistake. I'm dynamically building the secrets.yml file and was doing it in an initializer. Initializers fire after database.yml gets parsed so the secrets weren't available to database.yml.

over 1 year ago ·