I was trying to run specs via `RAILS_ENV=test rspec`. Pretty straight forward, right?
The rails app I was working on uses webpacker to compile assets. When running in a test environment, these assets are compiled to a "public/packs-test" directory. The "packs-test" directory is required in order to run the specs, so if it is missing, things go 💥! Well, this `packs-test` folder was not being created by webpacker, so my specs were all failing. 😭
Before we dive into what I discoverd. Let's review the order of precedence for environment variables.
Things are of course a little different between Windows, OSX and Linux environments. The list below is based on OSX/Linux, but I did want to mention a bit more on Windows Environment Variables.
Windows has a slight different order of environment variables:
Let's just consider all of these to be "System" in the order section below for simplicity.
This is how I imaged the order of environment variables. Essentially, "Command Line" will override "Zsh/Bash Shell Defaults" which will in turn override "System" level environment variables.
Tip: To view all your environment variables you can use `set` or `printenv` (osx/linux only)
Turns out, the way I was thinking about environment variables was wrong.
Although in most scenarios this order is true because of the typical sequence of operations, for example:
1) System environment variables are loaded by default when you start up your computer.
2) Shell defaults are loaded when you start your shell
3) Environment file overrides are loaded when you start your app
4) Environment variable is set via command, e.g. `RAILS_ENV=test rspec`
So, rather than thinking of environment variables as hierarchical order, a more accurate way of thinking about environment variables is that the last one set is the one used. It could be from the command line or from your bash profile or from setting it in your shell.
To demonstrate, let's consider that "FOO_BAR" is a standard environment variable defaulted to "BAZ" on every laptop.
```language-bash
❯ echo $FOO_BAR
BAZ
```
Overriding with Shell Session
```language-bash
❯ export FOO_BAR=1
❯ echo $FOO_BAR
1
```
Overriding with Command Line
```language-bash
❯ FOO_BAR=2 && echo $FOO_BAR
❯ echo $FOO_BAR
2
```
Overriding with Shell Session with Shell Defaults
Let's set the value in our shell via:
```language-bash
❯ export FOO_BAR=1
❯ echo $FOO_BAR
1
```
Now, if we were to add `export FOO_BAR=3` to our `.zshrc`, nothing would change in our current shell.
```language-bash
❯ echo $FOO_BAR
1
```
Cool. But, if we were to resource our shell, we'd lose our shell session and it would be set back to what is in the `.zshrc`.
```language-bash
❯ source ~/.zshrc
❯ echo $FOO_BAR
3
```
So, now that we have a fairly good understanding of how environment variables are set, let's dive into what happened to me.
I had a `.env.test` file with `RAILS_ENV=` in it, which was overriding my `RAILS_ENV=test` passed in via command line and subsequently `RAILS_ENV` was being defaulted to `production` because it was an empty string.
This is obviously not what I expected and did not even consider it because in my head I had already ruled it out. Shouldn't the `RAILS_ENV` that I pass into the command line always override? _Answer: nope!_
Turns out, the heart of the issue was that I did not realize how we were using the dotenv gem. When using the dotenv gem, you can load `.env` files via `overload` or `load`. The major difference between these two is that `overload` will override any existing environment variables set! Yes, you guessed it...we were using the `overload` method in the `test` environment, which in turn was overriding what I was passing in to the command line! 😳
To fix, I just removed `RAILS_ENV` from the `.env.test` file and then everything worked. 🎉
When you are hitting a wall...
Environment variables can be loaded in a myriad of ways and sometimes in unexpected ways. Be aware of the libraries you are using to load your environment variables especially.
Keep an open mind and question your assumptions. It can be hard to even be aware of them, so do what you can to get out of the 🤬 headspace.
Taking a short break and stepping away can help clear your head. By doing so, you will be able to be more aware of your assumptions and potentially attack your problem from an angle you did not consider.
This has been the single-most important thing I have adopted. No matter how frustrated you are or how hopeless you feel, do not give up.
More often than not you are just at the crest of the hill, just keep going!
Are you ready to build something brilliant? We're ready to help.