Set environment variable (ENV) for use in Rails - ruby-on-rails

Experimenting with MongoID on a Rails server and confused about how/where to set the environment variables.
config/mongoid.yml default template provides:
defaults: &defaults
host: localhost
...
# set these environment variables on your prod server
production:
host: <%= ENV['MONGOID_HOST'] %>
port: <%= ENV['MONGOID_PORT'] %>
username: <%= ENV['MONGOID_USERNAME'] %>
password: <%= ENV['MONGOID_PASSWORD'] %>
database: <%= ENV['MONGOID_DATABASE'] %>
My question is are these set in Rails somewhere? or are they at the system level? and if so where/how to set so that no user account needs to be logged in for them to be valid?

The ENV hash will have values from the system environment from when the rails process was started.
These can be set on the command line prior to starting the server or program. For example in bash:
export MONGOID_USERNAME='username'
These are only good for the life of your shell, unless you add them to your profile, but it is likely that your web server won't use that profile, so it is only useful for local development.
They can also be set, for example, in Apache with SetEnv. For example:
<Location /app >
SetEnv MONGOID_HOST 'localhost'
SetEnv MONGOID_PORT '8883'
SetEnv MONGOID_USERNAME 'username'
</Location>
This could be anywhere SetEnv is legal in your apache config, and that is the same context that your application lives under.
Regarding you comment about best practices, some people put an example yml config file in source control, and ignore the config/*.yml files from source control. When cloning a repository, copying and correcting the examples to the correct values is part of the setup, like running rake tmp:create to make the tmp folder structure.

I wanted to add another option here. On boot, Rails will attempt to read DATABASE_URL as a url and connect to a database from that env variable (ignoring database.yml). You should specify the database as:
DATABASE_URL="mysql2://user:pass#localhost/app_development" rails server
and you can verify this via:
DATABASE_URL="..." rails runner "p ActiveRecord::Base.connection_config"
This is just another option instead of putting erb settings into database.yml.

Related

password authentication failed for user "root" when dumping Rails schema as SQL

I am using Rails 5.2.3 with PostGIS 2.5 running on Postgres 11, set up in a Docker Compose environment. I've set the following in config/application.rb:
config.active_record.schema_format = :sql
So that special features in the Schema can get dumped. However, doing so during db:migrate, I get the following error:
pg_dump: [archiver (db)] connection to database "development" failed: FATAL: password authentication failed for user "root"
The command that gets executed is:
pg_dump -s -x -O -f /var/www/dev/db/structure.sql -T geography_columns -T geometry_columns -T layer -T raster_columns -T raster_overviews -T spatial_ref_sys -T topology development
The reason for the error is that there is no root user here; in fact, I am using a different username in my database config:
default: &default
adapter: postgis
encoding: unicode
host: <%= ENV['DATABASE_HOST'] %>
user: <%= ENV['DATABASE_USER'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
# For details on connection pooling, see Rails configuration guide
# http://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("DATABASE_POOL") { 10 } %>
The user is not root, and everything works fine from the Rails app itself, which can connect to the database using the user specified in the environment variable.
It just seems that pg_dump, when called from Rails to dump the schema, is not using the proper username from the config, but instead falls back to root.
I see some configuration environment variables in the source code, but how should I set them and why does Rails not do that by default?
I think it works when when, in my docker-compose.yml file I create an additional environment variable PGUSER that has the same value as DATABASE_USER. But that seems like workaround — is this a bug I'm seeing or some expected behavior?
The only solution I found so far was to specify an additional environment variable named PGUSER for the Rails container.
I assume this is a bug or not properly documented.

fe_sendauth: no password supplied encountered with Amazon RDS

I know many others have encountered this problem, but I'm limited in the Postgres configuration I can do since I am using Amazon RDS...
Here is the relevant section of my database.yml
default: &default
host: <%= ENV["POSTGRES_HOST"] %>
username: <%= ENV["POSTGRES_USER"] %>
password: <%= ENV["POSTGRES_PASSWORD"] %>
adapter: postgis
encoding: unicode
database: <%= ENV["POSTGRES_DB"] %>
port: 5432
pool: 5
When I hard code the host, leave everything else as is, and load localhost:3000, I get fe_sendauth: no password supplied error. However, when I hard code all of the values instead of using an ENV variable, everything loads as normal with no errors.
I'm using Amazon RDS, so I have no ability to edit pg_hba.conf, but is this just a simpler problem of RoR not having access to ENV variables?
Yup, it's pretty clear that your ENV values are returning nil. Keep in mind that environment variables are loaded a bit differently on your production server than localhost. In most deployment configurations you can't simply set a Unix environment variable and have it be detectable in ENV.
I can't really tell much about how your ENV variables are being set from your provided code, but you should consider using Figaro (https://github.com/laserlemon/figaro) or dotenv (https://github.com/bkeepers/dotenv) to manage your ENV variables for you. However, it will require the extra step of having to manage an environment variable file outside of source control.

Securely providing the database password in a Rails app

As you know, you MUST provide the correct database name, username, and password for the database in the config/database.yml file, or your Rails app will refuse to work.
In the default setup, your password is in plain text in the config/database.yml file. If your app is on a free GitHub repository, then your password is public information. This is not a viable option for a serious app. (It's OK for a tutorial exercise, provided that you don't use this password for anything else.)
I have a solution that has worked for me so far, but I'm wondering if there is something better. You can see my deployed example at https://github.com/jhsu802701/bsf .
What I do is set up the config/database.yml file to provide the username and password for the development environment programatically. For the development environment, I add commands to the config/database.yml script to acquire the development environment username (which is my regular username for the Debian Linux setup I use) and a blank password. (I give my username Postgres superuser privileges.) For the production environment, I add a command in the deployment script that acquires the username and password from files elsewhere on my account and writes this information to the config/database.yml file.
Is there a better solution?
Is there a Ruby gem that covers this? If not, I'm thinking of creating one.
The way that heroku does it, and a vast majority of other rails shops are with ENV variables
Export two variables to your environment,
export POSTGRES_USERNAME='username'
export POSTGRES_PASSWORD='password'
then in your database.yml file you can do
username: <%= ENV['POSTGRES_USERNAME'] %>
password: <%= ENV['POSTGRES_PASSWORD'] %>
This is how I make it work:
On terminal/cmd:
heroku config:set YOUR_DATABASE_PASSWORD=passywordy
Then, in /config/database.yml file;
production:
<<: *default
password: <%= ENV['YOUR_DATABASE_PASSWORD'] %>
(this password area is automatically generated when I used rails new my_app -d postgresql)
On other than heroku export you variables to system environment (linux) by typing in bash
export KEY=value
Then you can call it in Rails by ENV['KEY']
e.g.
in bash:
export CMS_DATABASE_PASSWORD=MySecurePassword
in secrets.yml:
password: <%= ENV['CMS_DATABASE_PASSWORD'] %>
Setting the environment variables as described in existing posts above, will only persist the environment variables for the duration of the current shell session.
To set the environment variables permanently, the export instruction(s) should be added to your shell config file. (Then run source ~/.bashrc to apply the changes to your current session)
TL;DR: If you're using BASH, add the export instruction(s) to ~/.bashrc.
While the above should suffice (if using BASH on most popular Linux distros), confidently identifying which config file to update for your shell can be quite tricky. The following post explains the reasons why and provides guidance on which config file to edit.
https://unix.stackexchange.com/questions/117467/how-to-permanently-set-environmental-variables

Mongohq and heroku setup

I am trying to use MongoHQ with my rails app which uses mongoid. I want to host the app at heroku. From the guide on heroku website, I should add this to my mongoid.yml:
production:
sessions:
default:
uri: <%= ENV['MONGOHQ_URL'] %>
options:
skip_version_check: true
safe: true
My question is, do I have to replace <%= ENV['MONGOHQ_URL'] %> with the URI of the following format:
MONGOHQ_URL: mongodb://<user>:<pass>#hatch.mongohq.com:10034/app003132345
I try replacing it and not replacing it. Either way, I got this error in the log (plus a bunch more, but I suspect this one).
MOPED: Could not resolve IP address for <myusername>
Are there anything else besides, adding this to mongoid.yml and add add-on for mongoHQ in heroku?
<%= ENV['MONGOHQ_URL'] %> is calling a value from the environment. If this were on your local machine you would have to enter the url in your environment.
However, Heroku is awesome and handles this for you! So all you need to do is use that code in your mongoid.yml. If you need to get the url to run your rails app in production on your local machine you can perform
heroku config --app your-app-here
This will print out all of the variables in your heroku environment for this app, including 'MONGOHQ_URL'. You can then copy this url (which will have the user and password filled out, so be careful about security!), and put it in your local environment by typing
export MONGOHQ_URL = url_from_heroku
This will keep the variable until you close your terminal session. However you can always have that variable defined if you add that line to your ~/.bash_rc file (or whatever your bash profile is)
Hope this helps!

rails 3: is there a way to put a gem's config params in environment.rb instead of foo.yml?

My rails app uses a gem that requires some config params to be specified in foo.yml:
development:
username: MyDevUserName
password: MyDevPassword
production:
username: MyPRODUserName
password: MyPRODPassword
I dont want the password in my source code and want to do something like:
development:
username: <%= ENV['THE_USERNAME'] %>
password: <%= ENV['THE_PASSWORD'] %>
production:
username: <%= ENV['THE_USERNAME'] %>
password: <%= ENV['THE_PASSWORD'] %>
However, for some reason that <%= ENV['XXX'] %> does work in my Settings.yml file, but does not work in my foo.yml file (I'm guessing however the foo gem loads the .yml file it does not allow interpretation).
So...
I'm wondering if Ruby/Rails has a general-purpose way to specify the variables in environment.rb instead of a foo.yml file?
Can i for example have an empty foo.yml file and add the following to environment.rb:
Foo::_something_._somethingelse =
{
:username => ENV['THE_USERNAME'],
:password => ENV['THE_PASSWORD']
}
EDIT: Since you are on Heroku...
Heroku is a different story. Your use of ENV may be conflicting with some functionality built into Heroku for handling config vars such as the ones you are working with. You need (drumroll, please)... CONFIG VARS. See this page in the Heroku Dev Center for information on how to set config vars in your Heroku deployment, how to access them from your app, and how to make it all work locally as well.
EDIT: Below is the original answer, still applicable in the general (non-heroku) case
Even if you put it in environment.rb, it will still be in your source code.
The correct way to do this is to ignore the foo.yml file in your version control (for instance, in git you would add the file to the .gitignore file). That way, you have the file locally where you need it, but it never gets committed to your repository, so your creds aren't exposed. On your deployment server, you will have to manually create that file as well, since when you deploy from source code the deployment won't have it.
If you are using capistrano for deployment, a common approach would be to put the file in [app]/shared/config/foo.yml, then add a deployment task to softlink from [sharedpath] into [releasepath]. Such a task in capistrano might look like this:
task :after_update_code do
run "ln -s #{shared_path}/config/foo.yml #{release_path}/config/foo.yml"
end

Resources