Rails Environment Variables
railsapps.github.com
railsapps.github.com
config/environments
├── config/environments/development.rb
├── config/environments/production.rb
└── config/environments/test.rb
Put all this stuff in there.edit: I see the source of this misunderstanding. The author states:
> Rails applications should be “turnkey”; that is, deployed anywhere without modifying code
This is an ideological statement with no basis in reality. If you have to jump through all these hoops in order to trick your app into running as expected without modifying code - you're probably Doing Things Wrong™.
A better approach might be to make a private fork of the project you wish to deploy, modify the code as needed, deploy from that, and periodically merge from upstream.
config.action_mailer.smtp_settings = {
address: "smtp.gmail.com",
port: 587,
domain: "example.com",
authentication: "plain",
enable_starttls_auto: true,
user_name: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
would be stored outside the codebase, not just the username and password. This seems to be accomplished with a tool like Foreman[2], mentioned at the end of OP under "Other Approaches".It's more work to set up, but does seem like it would be more reliable than your method. I like the idea of deploying an app anywhere without modifying code (only config details, stored separately). I've yet to work on a large SaaS app, but am studying the 12-factor manifesto to try to implement as much of it as possible when I do.
> A litmus test for whether an app has all config correctly factored out of the code is whether the codebase could be made open source at any moment, without compromising any credentials
This to me is a totally arbitrary and kind of silly "test". When was the last time you had to suddenly open-source an app you were working on? Never, right? Me neither. Why would I go to all this work to keep it "instant open-source ready"?
> As the project grows further, developers may add their own special environments like joes-staging, resulting in a combinatorial explosion of config
As a senior rails dev + team leader, the way I'd handle this is to tell "joe" not to commit his local junk to the repo. Otherwise I have never seen this "explosion" happen. I would certainly not go to all this effort - and introduce all this complexity - to work around what I consider to be an educational issue.
The whole 12-factor config thing just comes across as premature optimisation. If you actually find yourself having a problem that putting config in environment variables would fix - then fine, implement it. But no-one should be doing it up front. 99% of the time, you ain't gonna need it.
Additional things to think about:
* https://github.com/railsjedi/rails_config for local developer config
* There is a reason for autoloading: faster development. Even though you should not usually need to make app-specific configuration changes outside of the main environment.rb and each environment-specific config (development.rb, etc.), if you do, you might consider putting them into a module in an autoload path, and make sure that the fully-qualified path (A::B::C maps to something like app/models/a/b/c.rb) is correct, so that it autoloads without trouble.
* Some suggest putting constants for frequently used values in a file somewhere under config/initializers. That way Rails doesn't complain when reloading them. But, that doesn't autoload if you make changes in development.
* You can extend a Module that is autoloaded with methods that are "marked" with module_function :method_name to become private class methods on the class that extends them. This way you have non-inheriting methods that basically act like config variables.
* You can just use class_attribute in Rails to define inheritable attributes and then use self.the_class_attr_name = something to set them in the body of the class for configuration.
* attr_accessor :some_var_name, @@some_class_var, @some_instance_var, a hash, a Struct, or a OpenStruct are fine ways to hold config values and can be set inline for class vars, in the initialize method for instance vars, or methods called by other hooks, depending on what you need.
* Usually avoid $some_global_var as there is no way to tell whether it has been defined nor whether it has been set explicitly to nil.
That said, it's not been a terribly well maintained project. Haven't had time, needs help! I still use 0.2.5 since that's the only one that works for me :)
The rails-stripe-membership-saas example application [1] from the RailsApps project has become very popular. I've been getting lots of requests for help stemming from problems setting local environment variables. Personally, I prefer to use the Unix shell to set local environment variables such as email account credentials and API keys. Always has worked for me. Apparently some people have trouble (perhaps complications with rvm or just plain ignorance). Anyway, telling newbies to school up is not a solution. So Taylor Mock came up with a trick to use Ruby to set local environment variables from a Rails application without involving the Unix shell.
It has some advantages. If the variables are set in the shell, the code just works. If the shell environment is a mess, the developer can use a local_env.yml file to set the environment variables.
There are several other valid and appropriate approaches (a .env file, a dotenv gem, etc). Also, there is a whole mini-industry of clever gems for setting constants and configuration variables in Rails. This is different. This is just intended for variables such as email account credentials and API keys that shouldn't be hardcoded.
I describe the motivations for the article in a RailsApps blog post [2].
[1] http://railsapps.github.com/rails-stripe-membership-saas [2] http://blog.railsapps.org/
Another pro tip w/r/t environment variables: NEVER rely on $PATH - that should be considered a global variable that any arbitrary piece of code in your process can modify at will since everyone knows about it. I know Jruby use to rely on this for their Ant integration and it was annoying as hell before it was fixed.
I'm conflicted about it though; I hate being out of the mainstream on something as fundamental for maintenance as this and I have to jump through hoops to get Apache to set my environment variables.
I tend to favor YAML files for configuration, and symlink them in the case of security concerns like private keys.
To roll up a standard access pattern in our app which has dozens of configuration files, I wrote this which allows local developer overrides via xxx_local.yml:
https://gist.github.com/4280751
I'll probably gemify it at some point.
exemple:
if ENV["NO_REDIS_CACHE"]
config.cache_store = :null_store
else
config.cache_store = :redis_store
endIn development if we need to try something without cache, and in staging and tests for some tests runner (integration tests, QA crawlers, ...).
The more common case I've come across is that devs who leave their passwords hard coded do so because they are inexperienced and know of no other way. I wish the best practice were the default in this situation