

Rails Environment Variables - aviflombaum
http://railsapps.github.com/rails-environment-variables.html

======
venus
As far as I can see this article is rather misguided. The author seems totally
unaware of the existence or purpose of these files:

    
    
      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.

~~~
graue
I've been reading "The Twelve-Factor App" today, which goes even farther and
suggests a strict separation of code and config[1]. In which case, presumably,
all of these settings:

    
    
        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.

[1] <http://www.12factor.net/config>

[2] <https://github.com/ddollar/foreman>

~~~
venus
I read the "Twelve Factor" article you linked to and .. well, I just disagree.

> 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.

------
habosa
This is extremely useful. A TON of people learn Rails from tutorials and never
hear about issues like this. Then they go and push to GitHub and expose their
login information for something secure. It took me too long to figure this
out, thankfully nobody really looks at my Rails projects on GitHub (I hope).

------
DanielKehoe
Taylor Mock and I are the authors of the article. Here's why we wrote the
article. And why we suggest an alternative to using the Unix shell to set
local environment variables.

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/>

~~~
strife25
Totally agree on your thoughts with relying on env. variables - I hit the same
issue with trying to write re-usable Chef code.

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.

------
petewarden
I've wrestled with this pattern (anti-pattern?) myself. One key advantage is
that I can run plain Ruby unit tests outside of Rails, as long as I make sure
the right environment variables are set in my shell.

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.

------
dasil003
Interesting article as I haven't gone down this path.

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.

~~~
aviflombaum
I like that they present solutions that let you load ENV vars from YAML, sort
of like a best of both worlds. Maintaining ENV Shell across multiple servers
is even harder so YAML works well.

~~~
dasil003
I think the reason it hasn't become more of an issue for me is that I use more
Engine Yard and VPS than Heroku.

------
itsbonczek
I've been really liking the foreman approach with Heroku. It's super easy to
create a .env file that contains environment variables that can then be git-
ignored.

------
calgaryeng
You can also check out the `figaro` gem which provides some pretty handy
functionality.

~~~
jacquesc
Wow, this gem actually looks pretty rad. Here's a link
<https://github.com/laserlemon/figaro>

------
mickeyben
I love this hack. We're using it a lot at our company.

exemple:

    
    
      if ENV["NO_REDIS_CACHE"]
        config.cache_store = :null_store  
      else
        config.cache_store = :redis_store  
      end

~~~
jherdman
That's kind of interesting. One would think the :null_store would only be
useful in some environments, and not as something you may want, for example,
in production. In what capacity are you using this?

~~~
mickeyben
We're using this in development, staging and test. But only in some
circonstances.

In development if we need to try something without cache, and in staging and
tests for some tests runner (integration tests, QA crawlers, ...).

------
danso
Dear god....this has always been a point of confusion for me, in that if you
look up best practices, you'll find a multitude of contradictory advice. Well,
I guess all solutions could be equally safe and sound...but it was still
confusing and something almost never covered in beginner how-tos. I'm glad I'm
not the only one who was always mildly confused.

~~~
dasil003
I think the issue is that it's highly environment-specific and there's no
single best practice aside from general principles like "don't store passwords
in your repo".

~~~
haakak
I'm not sure that I'd even go so far as to say no passwords in the repo. In
some environments, the developer is the only one with access to DB and the app
code, and there is no growth planned (no separation of responsibilities), in
which case it is acceptable even if not optimal to have them in database.yml.

~~~
danso
Yes, but the developers who know how to then remove such hard coded variables
and then where to store them will, out of habit, go the extra step, even if
out of paranoia, because such a step is likely forgotten when the repo
suddenly needs to be opened up

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

