Using Figaro and Dotenv gems in Ruby

A few weeks ago I worked on my first Sinatra app that required access to AWS s3 bucket. Accessing Aws was pretty easy using the aws-sdk gem. Since my credentials were already set in ~/.aws/credentials I could easily access Aws and it’s resources now.

However, my need was to access a specific s3 bucket and the objects within it. Again, Amazon was kind enough to contain code examples in their documentation. I just needed to tweak it a bit to work for me. My objective was to delete specific objects with the S3 bucket after receiving a payload from GitHub webhook actions and I could!

My hurdle came when I realized I had hard-coded values that could be made configurable by passing them as environment variables based on the twelve-factor App methodology. PS: I have no clue why it’s called the twelve-factor App but along the way I have come to appreciate having configs for different environments i.e stage, production. I don’t have to keep changing code based on which environment I need to deploy to.

Here is an extract from one of the AWS code examples:

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX - License - Identifier: Apache - 2.0
require 'aws-sdk-s3'

# Uploads an object to a bucket in Amazon Simple Storage Service (Amazon S3).
#
# Prerequisites:
#
# - An S3 bucket.
# - An object to upload to the bucket.
#
# @param s3_client [Aws::S3::Client] An initialized S3 client.
# @param bucket_name [String] The name of the bucket.
# @param object_key [String] The name of the object.
# @return [Boolean] true if the object was uploaded; otherwise, false.
# @example
# exit 1 unless object_uploaded?(
# Aws::S3::Client.new(region: 'us-east-1'),
# 'doc-example-bucket',
# 'my-file.txt'
# )
def object_uploaded?(s3_client, bucket_name, object_key)
response = s3_client.put_object(
bucket: bucket_name,
key: object_key
)
if response.etag
return true
else
return false
end
rescue StandardError => e
puts "Error uploading object: #{e.message}"
return false
end
# Full example call:
def run_me
bucket_name = 'doc-example-bucket'
object_key = 'my-file.txt'
region = 'us-east-1'
s3_client = Aws::S3::Client.new(region: region)
if object_uploaded?(s3_client, bucket_name, object_key)
puts "Object '#{object_key}' uploaded to bucket '#{bucket_name}'."
else
puts "Object '#{object_key}' not uploaded to bucket '#{bucket_name}'."
end
end
run_me if $PROGRAM_NAME == __FILE__

As you may notice, thebucket_name , object_key and region are all hard-coded values that can vary based on the environment.

And here comes the Good news! There are a couple of ruby gems that allow you to set environment variables and secure them. That way you can add your Aws access keys without worry that they will be exposed on Github.

I first tried out Figaro which is highly recommended in the Ruby community. Here is how Figaro works:

  1. Add gem "figaro" to your gemfile
  2. Run bundle exec figaro install on your terminal. This will create a config/application.yml file and add it to .gitignore
  3. You can then add set your environment variables within the application.yml file.
aws-bucket-name: 'us-east-1'

4. You can then easily access them like so :

bucket_name = ENV["aws-bucket-name"]

This would work well in Ruby on Rails but after days of trying it out in Sinatra and research, I realized it was never built for Sinatra. There is, however, this branch that could probably work for anyone interest in using Figaro in Sinatra.

I decided to take a different route and discovered dotenv another Ruby gem that has support for Sinatra apps as well. You,however, need to add your .env (where your configs reside in) to the .gitignore by yourself. The gem doesn’t do it for you.

This is how it works:

  1. Add gem dotenv to your gem file and run bundle install
  2. Create a .env file and add your environment variables like so:
aws_region='us-east-1'bucket_name='my-bucket'

3. In your .rb file add, add the following:

require 'dotenv'
Dotenv.load

4. You can access the environment variable as follows:

bucket_name = ENV["bucket_name"]
region = ENV["aws_region"]

5. Don’t forget to add the .env file to .gitignore

That is it, an easy way to make environment variables configurable and maintain good coding practices in Ruby!😊

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store