Custom Rails configuration

The Rails apps I work with have varying levels of configuration. Some require credentials files while others shove a few variables in application.rb. There are applications using .env and some with constants littered across the codebase.

But there’s one common thread. They all require some environment-based configuration that isn’t secret. Configuration that doesn’t change often but is used throughout the codebase. Stuff we don’t mind checking in to source control.

I started using ActiveSupport::OrderedOptions to configure a few variables in my Rails app. I like how the API gives me clean, explicit, and fail-fast feedback. Also, it’s built into Rails!

Let’s walk through different ways of adding custom configuration to a Rails app. We will use email addresses in our examples.

Basic configuration

For single variables that are constant across environments you can add a variable directly to your Rails application file. Here I’m adding a support email address to be used in my mailers and the public support page.

# config/application.rb`

module MyApp
  class Application < Rails::Application
    config.support_email = "joe@masilotti.com"
  end
end

Attaching configuration directly to the application is the most straightforward approach. It can be accessed directly, as well.

Rails.configuration.support_email # => "joe@masilotti.com"

You can also override these values in the environment specific configuration files like config/environments/development.rb and production.rb.

Nested configuration

You can nest configuration to associate a few values under a single namespace. In this example I have two email addresses, one for support and one for marketing.

# config/application.rb`

module MyApp
  class Application < Rails::Application
    config.x.emails.support = "joe@masilotti.com"
    config.x.emails.marketing = "hi@masilotti.com"
  end
end

Accessing them follows the same approach as above, the addition of the x.

Rails.configuration.x.emails.support # => "joe@masilotti.com"
Rails.configuration.x.emails.marketing # => "hi@masilotti.com"

More complex configuration

This works great for a few variables. But what happens when you have 15 email addresses to configure? And they are all different based on the environment? All those lines of code would only muddy up application.rb.

Enter Rails::Application.config_for, a helper method to load entire configuration files. Here’s how it works. First, create a YAML file holding all of your configuration.

# config/emails.yml

shared:
  support: joe@masilotti.com
  marketing: hi@masilotti.com
  # Many more email addresses...

Next, load the file with config_for in your application file.

# config/application.rb

module MyApp
  class Application < Rails::Application
    config.emails = config_for(:emails)
  end
end

You can now access these values like before. And without the additional x.

Rails.configuration.emails.support # => "joe@masilotti.com"
Rails.configuration.emails.marketing # => "hi@masilotti.com"
Rails.configuration.emails.sales # => nil

Oh, wait a minute. Why did #sales return nil? Shouldn’t a missing value raise an exception or something?

Raise on nil values

Glad you asked! Add a bang at the end of the call and Rails will raise an error if the value doesn’t exist.

Rails.configuration.emails.sales! # => KeyError: :sales is blank

Environment-specific configuration

The YAML file can also be extended to provide environment-specific configuration. Note the shared: key at the top? That will apply across all environments. But providing environments as keys will override the shared values.

# config/emails.yml

shared:
  support: joe@masilotti.com

production:
  support: support@masilotti.com

Now, in development we will get joe@masilotti.com but in production support@masilotti.com. No changes are needed to application.rb.

More information on Rails configuration can be found in the Configuring Rails Applications guide.

Real world example

I’m using this in production on RailsDevs, my open source Rails app. I have a few email addresses configured and pull them in on support pages and mailers.

It works really nice for Rails configuration that changes infrequently, might differ across environments, and doesn’t need to be kept secure. Keeping these directly in the codebase makes onboarding new developers to the OSS project easier.