Hire Us
Rails configuration in the proper way

Rails configuration in the proper way

Usually Rails application has multiple environments – production, development, test and staging; and quite often application behaves differently in each environment. Rails provides a simple way to inspect current environment:

> Rails.env
=> "development"
> Rails.env.development?
=> true

But abusing Rails.env for adjusting application behaviour leads to serious issues with future configuration changes. We’ll discuss these issues below, along with the proper way to deal with them.

1. Change your configuration not a code

Let’s say we want to force SSL protocol for user’s settings page. With Rails.env it’s easy to do, just place the following line into your UsersController:

  force_ssl if Rails.env.production?

The main issue with this approach is that code is not flexible. Just when SSL should be forced for ‘staging’ environment, we should change the code. That’s not so difficult if condition is used only once, but in case when SSL is required in multiple places, it becomes pain in the neck.

We can use YAML file to put all ducks in a row. Here’re SSL settings placed into ‘config/settings/ssl.yml’:

development:
  enabled: true

production:
  enabled: false  

test:
  enabled: true

I’ll use global gem to get OOP interface for this YAML:

  force_ssl if Global.ssl.enabled

You can read more about global gem and configuration with it here.

After this refactoring we can change behaviour without making changes in the code. To enable SSL for development environment, we should only enable option in YAML file. In case when this code was spread across different places, this approach saves a lot of time.

2. Use configurations over conditions

In the new example, our application should provide different title on the main page for each environment:

def main_page_title
  if Rails.env.production?
    "My App"
  else
    "My App #{Rails.env}"
  end
end

To avoid conditions we can replace this code with ‘config/settings/text.yml’:

development:
  main_page_title: "My App development"

production:
  main_page_title: "My App"

test:
  main_page_title: "My App test"

Now ‘main_page_title’ method is replaced with:

  Global.text.main_page_title

Such declarative approach helps us avoid environment dependency in the code, removes batch of dump methods like ‘main_page_title’ and makes code more flexible.

3. Write code that means something

I found this piece of code in one of the projects:

<%if Rails.env.production? || Rails.env.staging? %>  <%end%>

It was really hard to understand what this is and why it should be included only in production and staging environments until this commit message from the git log helped me: “Add tracking code to layout”

Again, we put configuration into ‘config/settings/marketing.yml’:

development:
  tracking:
    enabled: false

production:
  tracking:
    enabled: true

staging:
  tracking:
    enabled: true

test:
  tracking:
    enabled: false

And the code looks like this:

<%if Global.marketing.tracking["enabled"] %>  <%end%>

Now we can read it properly: “When tracking for marketing is enabled include this “magic” javascript”.
Here we gain a very important value: code tells us about its intention.

Conclusion

If you’re going to use Rails.env in your code, it’s time to think about configuration as it’ll help you make code: short, readable, and maintainable.