rails-config

Rails configuration in the proper way

| 13 Comments

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:

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:

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':

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

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:

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

Now ‘main_page_title’ method is replaced with:

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:

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':

And the code looks like this:

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.

Share
* Railsware is a premium software development consulting company, focused on delivering great web and mobile applications. Learn more about us.
  • robert

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

    goes to

    def main_page_title
    “My App” + (Rails.env.production? ? Rails.env : ”)
    end

    if you prefer one line :)

    • Mugsx

      Nearly – although your logic is around the wrong way, I think – you append the environment name only in production!

      def main_page_title
      “My App” + (Rails.env.production? ? ” : Rails.env)
      end

      But then you get “My Appdevelopment”, so we need a space too:

      def main_page_title
      “My App” + (Rails.env.production? ? ” : ‘ ‘ + Rails.env)
      end

      It’s one line, sure, but not exactly pretty, and I suggest the intention is far from obvious at a first glance!

  • Sergii

    Interesting to see how huge your *.yml is and how easy is to go throughout envs to find out all possible values.

    • Olexander Paladiy

      Don’t put all settings into one file. You should split your settings across multiple yaml files so each file will have small batch of settings and single responsibility:
      Global.ssl.enabled from ssl.yml
      Global.marketing.tracking[“enabled”] from marketing.yml

  • Guest

    I find the grammatical errors distracting.

  • http://www.codesherpas.com David Bock

    This is a fantastic article, and your examples illustrate clearly how you can take a simple environment check and instead make it a ‘fluent’ description of *why* you’re checking rather than *what* you’re checking.

    I also like the recommendation of the global gem, as it will automatically key off the environment for you. for smaller cases though, you can just as easily use the built in config hash in Rails:

    Application.config.my_property = “Schpoo”

    Application.config is a HasWithIndifferentAccess, and you can stick your own things into it. If you put values in from your config/environments//rb file, it will naturally have a value appropriate for the current environment.

    • Olexander Paladiy

      Thanks David. I agree with you that Application.config is useful for small batch of settings, but it can be hard to read them with big amount of options.

  • Chuck

    The 12 factor app addresses this: http://12factor.net/ Specifically: http://12factor.net/config

  • http://www.wddx.ru Mokevnin Kirill
    • Vladimir Melnick (rubydev.ru)

      DSL is a good idea, but it too difficult for this task. The best solution is immutable (deep frozen) ruby hashes.

  • Georgiii

    Thanks for the awesome article!

  • nandosousa

    Awesome! i’ll put this in practice.

  • Pingback: Share Rails configuration to Javascript | Railsware Blog()

Want to get more of Railsware blog?

RSS FEED

We're always ready to help!

CONTACT US