Setting Up Postgres for Local Rails Development
Note: I am going to assume you have at least a little bit of experience in working with a Ruby on Rails app.
Why the post?
Professional Ruby on Rails developers will always recommend that your local development environment match your production environment to help catch bugs that occur due to inconsistent database implementations of the same feature. Having something work locally in SQLite3 but not in Postgres is actually a common enough problem that this mantra is often repeated, but leaves the Junior dev learning proper Rails development to their own devices when it comes to actually setting up Postgres on their local environment.
This blog post is an attempt to remedy that situation and also be a quick reference for those who only occasionally touch Postgres when they absolutely need to.
Installing Postgres
The first thing we need to do is actually get Postgres installed on our local
machine since it’s required by the pg
gem.
Most distributions will have a recent-ish version of Postgres available from the built-in package manager without prior setup requried.
For Debian/Ubuntu this should get you set up and running:
$ sudo apt update
$ sudo apt install postgresql libpq-dev
For Homebrew on macOS:
$ brew install postgresql libpq-dev
For other operating systems you can consult the official Postgres downloads page.
Now we need to actually get Postgres running. Most Unix-like OSes have the
system
command for starting, stopping, and checking the status of different
services. If the following command doesn’t work, double check the Postgres
startup process for your specific operating system.
$ sudo service postgresql start
If the above command worked you should see something like this in your terminal:
* Starting PostgreSQL 10 database server [ OK ]
rails new
Next we’re going to set up a toy rails app so we can make sure our database connection actually works from Rails (you can always just use an existing app but for demonstration purposes we’ll be starting fresh).
$ rails new test_app --database=postgresql
$ cd test_app
Next we’re going to add an Account model to the app so we have something to migrate against the database.
$ rails generate model Account username:string
In this model we’ve created a table named Account with a username field of type string. We won’t be migrating this just yet, so hang tight for that.
The database.yml file
Our next step is to setup the config/database.yml
file so it points to our
(currently non-existant) database and database user.
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
host: localhost
port: 5432 # This is the default, but you may need to change this.
username: test_app
password: test_app
development:
<<: *default
database: test_app_dev
test:
<<: *default
database: test_app_test
The production
settings are omitted as they’re going to vary depending on your
deployment and we only want to focus on getting Postgres running locally.
Creating the Databases
The next step is to create the test_app
role which our app will be using to
log into Postgres in order to create, drop, or modify data.
$ sudo -u postgres psql
postgres# CREATE ROLE test_app WITH CREATEDB LOGIN PASSWORD 'test_app';
postgres# \du
After following the commands, we should now see an output table of the Postgres
roles, and our new test_app
user should be on the list.
List of roles
Role name | Attributes | Member of
--------------+------------------------------------------------------------+-----------
postgres | Superuser, Create role, Create DB, Replication, Bypass RLS | {}
test_app | Create DB | {}
Now we need to give this new user some databases.
postgres# CREATE DATABASE test_app_dev OWNER test_app;
postgres# CREATE DATABASE test_app_test OWNER test_app;
postgres# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
---------------+----------+----------+---------+---------+-----------------------
postgres | postgres | UTF8 | C.UTF-8 | C.UTF-8 |
template0 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | C.UTF-8 | C.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
test_app_dev | test_app | UTF8 | C.UTF-8 | C.UTF-8 |
test_app_test | test_app | UTF8 | C.UTF-8 | C.UTF-8 |
(5 rows)
Perfect, we now have our test_app
user, and our test_app_dev
and
test_app_test
databases. We can now go ahead and perform the migration to make
sure everything went well.
Putting it all together
Finally, we’re going to pop back out of psql and run our Rails migration.
postgres# \q
$ rails db:migrate
Give it a bit of a second and if it was successful you should now see a terminal
printout of the account
table you just created.
== 20180925153232 CreateAccounts: migrating ===================================
-- create_table(:accounts)
-> 0.0251s
== 20180925153232 CreateAccounts: migrated (0.0251s) ==========================
NOTE: If you get an error similar to the following, make sure Postgres is both
running and that the port set in the database.yml
file matches the port
Postgres is using. You can get the port that Postgres is setup to use by running
service postgresql status
.
PG::ConnectionBad: could not connect to server: No such file or directory
Is the server running locally and accepting
connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
Conclusion
Now that we’ve setup our local Postgres environment we can easily develop and test against Postgres’ specific quirks and differences from other database management software.
Now that you’re using the same database on all environments, you can even start using (and testing with) Postgres-specific SQL features you won’t find in other DBMSes. This is probably the best part of all, since now you’ll finally be able to use all those features you’ve been hearing about that Postgres has, like SQL Views.