This guide is intended for a Rails application that uses PostgreSQL and is tested, developed, and deployed using Docker. The following link is a setup guide for a Rails + PostgreSQL application using Docker:
https://gist.github.com/iEv0lv3/17e33bc8d3ad4132d317ba5a1cf62d9b
The guide assumes the above Docker + Rails setup is complete. The approach in this guide creates a new Rails environment: staging, and the only responsibility of the staging environment is to be used with CircleCI for CI/CD testing. The environment name can be whatever you'd like, ci, cd, or circleci would all work as environment names as well. Why I prefer this approach is because it allows the use of standard CircleCI environments for the build and test jobs that utilize native CircleCI images for Ruby and PostgreSQL. It also allows for a high degree of customization for CircleCI without affecting Docker test, development, and production deployments.
Completing the entire guide is required to ensure all functionality works as expected, but the primary factor that makes this build work is overwriting the default host: db in config/database.yml
...
# config/database.yml
staging:
<<: *default
database: my_app_staging
host: 127.0.0.1
Updating the config/database.yml file with the above code enables CircleCI to use the standard PostgreSQL image: circleci/postgres:12.3, and run it locally on 127.0.0.1. This guide requires Rails 6 in order to use credentials.
There is an alternative approach that creates a Linux environment in the .circleci/config.yml setup using an Ubuntu image, and then adds all necessary dependencies to run Docker and Docker Compose within that environment. The alternative approach allows for the use of docker-compose build to build a test environment in CircleCI, which creates containers based on the project's Dockerfile. The images built from the Dockerfile are used in place of standard images from CircleCI. A standard image configuartion for CircleCI and a Rails app generally includes:
# .circleci/config.yml
docker:
- image: cimg/ruby:2.7.1-node
- image: circleci/postgres:12.3With my current level of Docker knowledge I find the alternative approach to be more cumbersome and prone to errors, but it is a valid solution to use with CircleCI.
- Open
Gemfile- Add
gem ‘rspec_junit_formatter’
- Add
- Result
- Solves a test formatting error when running RSpec tests
The following steps create the staging environment in Rails
- Add
staging.rbtoconfig/environments - Copy contents of
config/environments/test.rbintoconfig/environments/staging.rb
Here is a resource to help understand creating new Rails environments
- Open
Gemfile- Add
:stagingenvironment to Gem group that also includes:testand:development
- Add
- Open
database.ymland add
...
staging:
<<: *default
database: my_app_staging
host: 127.0.0.1
...- Open
webpacker.ymland add
...
staging:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
...- Run
rails cRails.application.credentials.config- Copy
secret_key_baseand it’s value - Close
rails c
- Edit
stagingenvironment credentials in terminalEDITOR=“code --wait” bin/rails credentials:edit --environment staging- In the above command replace
codewith yourIDEof choice
- In the above command replace
- A file will open that can be edited
- Add
secret_key_base: <paste value>to file - Close file and it will save and encrypt
Here are some resources to help understand Rails credentials
- https://guides.rubyonrails.org/security.html#environmental-security
- https://blog.saeloun.com/2019/10/10/rails-6-adds-support-for-multi-environment-credentials.html
- Open
.gitignore- Add
/config/credentials/staging.key
- Add
- Open
.circleci/config.ymland ensure these environment variables are set correctly
jobs:
test:
docker:
- image: circleci/postgres:12.3
environment:
POSTGRES_DB: my_app_staging
environment:
RAILS_ENV: staging
PGHOST: 127.0.0.1- Open project on
CircleCI.com- Open project options
- Add Environment Variable
RAILS_MASTER_KEY: <staging.key value>
version: 2.1 # Use 2.1 to enable using orbs and other features.
# Declare the orbs that we'll use in our config.
orbs:
ruby: circleci/ruby@1.0.6
node: circleci/node@3.0.1
jobs:
build: # our first job, named "build"
docker:
- image: cimg/ruby:2.7.1-node # use a tailored CircleCI docker image.
steps:
- checkout # pull down our git code.
- ruby/install-deps # use the ruby orb to install dependencies
# use the node orb to install our packages
# specifying that we use `yarn` and to cache dependencies with `yarn.lock`
# learn more: https://circleci.com/docs/2.0/caching/
- node/install-packages:
pkg-manager: yarn
test: # our next job, called "test"
# we run "parallel job containers" to enable speeding up our tests;
# this splits our tests across multiple containers.
parallelism: 3
# here we set TWO docker images.
docker:
- image: cimg/ruby:2.7.1-node # this is our primary docker image, where step commands run.
- image: circleci/postgres:12.3
environment: # add POSTGRES environment variables.
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
POSTGRES_DB: my_app_staging
# environment variables specific to Ruby/Rails, applied to the primary container.
environment:
BUNDLE_JOBS: "3"
BUNDLE_RETRY: "3"
PGHOST: 127.0.0.1
PGUSER: postgres
PGPASSWORD: password
RAILS_ENV: staging
# A series of steps to run, some are similar to those in "build".
steps:
- checkout
- ruby/install-deps
- node/install-packages:
pkg-manager: yarn
# Here we make sure that the secondary container boots
# up before we run operations on the database.
- run:
name: Wait for DB
command: dockerize -wait tcp://localhost:5432 -timeout 1m
- run:
name: Database setup
command: bundle exec rails db:schema:load --trace
# Run rspec in parallel
- ruby/rspec-test
# We use workflows to orchestrate the jobs that we declared above.
workflows:
version: 2
build_and_test: # The name of our workflow is "build_and_test"
jobs: # The list of jobs we run as part of this workflow.
- build # Run build first.
- test: # Then run test,
requires: # Test requires that build passes for it to run.
- build