A gift wrapped in pink paper

Nick Fewings

Wrap your environment variables in a settings object

In our applications, we often use environment variables to configure the application itself or connections to third party services. These values are then accessed through the special ENV hash provided by Ruby.

Instead of…

…using environment variables in your code:

app/views/layouts/application.html.erb

...
<% if ENV["ANALYTICS_TOKEN"] %>
<script>
  window.analytics_token = <%= ENV["ANALYTICS_TOKEN"] %>
  ...blah_js...
</script>
<% end %>
...

Use…

…an object to wrap your configuration:

config/initializers/settings.rb

class Settings
  class << self
    def analytics?
      !!analytics_token
    end

    def analytics_token
      ENV["ANALYTICS_TOKEN"]
    end
  end
end

app/views/layouts/application.html.erb

...
<% if Settings.analytics? %>
<script>
  window.analytics_token = <%= Settings.analytics_token %>
  ...blah_js...
</script>
<% end %>
...

Why?

The major benefit here is the encapsulation of environmental settings, tokens & configuration into one place. Rather than using ENV variables throught your code base, now you have a single place to translate environment variabes into your app.

I also find this style to be more attractive in usage than querying the ENV hash.

Further improvements?

You can use ENV.fetch("VARIABLE_NAME") within the Settings object to raise errors if an ENV value is required by your application and is not present.

As your environment becomes more complex you might use multiple (very similar) objects, perhaps to separate out Settings and Tokens.

Why not?

This is a style and organisation improvement that’ll have the most impact on slightly larger projects.

There is the encrypted credentials functionality built into versions of Rails after 5.2. The documentation on that Rails feature is brief at best and I’ve never got on with it. If you mainly deploy to Heroku you might prefer to keep configuration in the environment as argued for in the twelve-factor manifesto.

There are also gems that provide similar wrappers around your ENVironment, but I’ve never found one that had as clear and effective API as building your own configuration object.

Last updated on May 10th, 2021