When you generate a Ruby on Rails application it will create three environments: * development * production * test
each has a corresponding configuration file:
- config/environments/development.rb
- config/environments/production.rb
- config/environments/test.rb
The purpose of those environments is to configure the Ruby on Rails framework. Rails guide link.
In development mode Rails reloads all app classes and turns off caching to allow a faster development cycle. This is how the app runs on a development workstation.
In production mode all caching is turned on, often pointing to a memcached server. This is how the app runs on the live server.
The test mode is used in the tests, we have a special throw away database used only for test, wiped out between test runs.
These are the Rails default environments.
What I’ve often seen are extra Rails environments such as:
- develop – a development server used only for development tests
- staging/pre_production – a server where stakeholders can test stories on an environment as similar to production as possible
rhat I usually see is those extra environments are a perfect copy of config/environments/production.rb
.
So I started wondering what’s their purpose?
I can tell you what their purpose used to be for me.
In the past I used the map each Rails environment to a server stage, and use them to load configuration and set behaviour.
I used to think having a YAML file to load configuration was a neat solution to setting configuration on different stages. And I am pretty sure I wasn’t alone, here is an old Railcast about that.
Now I’d rather put that configuration in an unix ENV variable and have the code load it from there. This link covers this approach.
Each server stage will be provisioned with apropriate ENV variables (ie. S3BUCKET).
Look at foreman or dotenv to use the env variables approach in development mode.
Another thing I used to do what turning on some behaviour on specific stages. This wasn’t feature flagging but simply a server stage dependent behaviour.
Turning on behaviour on specific server stages
If the separate Rails environment is only used for feature toggling (ie. display a different header to differentiate the staging site from production site) do we really need a separate Rails environment for that?
Why not having as part of the server provisioning a unix variale (ie. STAGE=’staging’) set to the server stage?
In Rails instead of:
if Rails.env.staging?
# do stuff
end
we will use:
if ENV['STAGE'] == 'staging'
# do stuff
end
If you find typing that often a simple helper could be introduced:
class ServerStage
def self.current
ENV['STAGE']
end
def self.staging?
current == 'staging'
end
end
if ServerStage.staging?
# do stuff
end
Conclusion
My suggestion is to run both staging and production servers using the Rails production environment unless there are Rails configuration differences between them.
What’s your opinion? I am curious to see if I missed some useful application of Rails environments or overlooked at downside of ENV variables.