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.
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 = "email@example.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 # => "firstname.lastname@example.org"
You can also override these values in the environment specific configuration files like
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 = "email@example.com" config.x.emails.marketing = "firstname.lastname@example.org" end end
Accessing them follows the same approach as above, the addition of the
Rails.configuration.x.emails.support # => "email@example.com" Rails.configuration.x.emails.marketing # => "firstname.lastname@example.org"
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
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: email@example.com marketing: firstname.lastname@example.org # 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
Rails.configuration.emails.support # => "email@example.com" Rails.configuration.emails.marketing # => "firstname.lastname@example.org" Rails.configuration.emails.sales # => nil
Oh, wait a minute. Why did
nil? Shouldn’t a missing value raise an exception or something?
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
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: email@example.com production: support: firstname.lastname@example.org
Now, in development we will get
email@example.com but in production
firstname.lastname@example.org. No changes are needed to
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.