By Lucas Caton

Five small hacks for your Ruby projects

Here are a few small hacks I have discovered over the years to streamline your Ruby projects.

1. Valid date method

Many projects require a method that takes a date as a parameter and returns the date if it is valid and false if it is not. This method should also not raise an exception.

Regex is the obvious go to but that is not a great idea. Here is an example of the sort of code you would need to write to check a date:

def valid_date(potential_date)
  ) ? potential_date : false

Once upon a time, I would have used the Date.parse method to validate dates. However, I soon learned that it comes with a number of gotchas, as illustrated below:

def valid_date(potential_date)
rescue ArgumentError

The examples below behave as expected:

puts valid_date("2018-05-04")
#=> <Date: 2018-05-04>

puts valid_date("something else")
#=> false

However, the following example can catch you out:

Date.parse "hel10 world"
#=> #<Date: 2018-05-10>

This is because Ruby sees the 10 and assumes that you mean the tenth day of the current month and year. Go figure!

You really want to pass in a format, but there are many valid date formats. This can be achieved by providing a list of formats using ||=. As we loop through each format, Ruby may raise an exception if the format is not a match. We need to capture that exception and find a way to resume the code.

This is achieved by the following method:

def valid_date(potential_date)
  formats ||= ['%Y/%m/%d', '%d/%m/%Y', '%m/%d', '%B %d', '%b %d', '%d %b']

  format = formats.shift

  Date.strptime(potential_date, format).tap do |date|
    confirmation = date.strftime(format)
    raise ArgumentError if potential_date != confirmation
rescue ArgumentError
  formats.any? ? retry : false

2. Using hashes in RSpec to check different variable/value combinations

Often in RSpec, you want to check all different combinations of values for a number of variables, such as in the following example:

RSpec.describe RealStateWorker do
  context "when active is true and rented is true" do
    it { expect(something).to eq(something) }

  context "when active is true and rented is false" do
    it { expect(something).to eq(something) }

  context "when active is false and rented is true" do
    it { expect(something).to eq(something) }

  context "when active is false and rented is false" do
    it { expect(something).to eq(something) }

Because each variable has two possible values, there are four combinations to test. But, what if we had more variables? This can very quickly grow out of hand. Using hashes is a concise way of managing this:

RSpec.describe RealStateWorker do
  scenarios = [
    { active: true,   rented: true,  expected_result: :something      },
    { active: true,   rented: true,  expected_result: :something_else },
    { active: true,   rented: false, expected_result: :something      },
    { active: true,   rented: false, expected_result: :something_else },
    { active: false,  rented: true,  expected_result: :something      },
    { active: false,  rented: true,  expected_result: :something_else },
    { active: false,  rented: false, expected_result: :something      },
    { active: false,  rented: false, expected_result: :something_else }

  scenarios.each do |scenario|
    context "when active is #{scenario[:active]} and rented is #{scenario[:rented]}" do
      it "is #{expected_result}" do
        expect(something).to eq(scenarios[:expected_result])

3. Manage white labelling a website using a YAML file

White labelling a website can get very messy very quickly. I streamline the process by creating a Brandable concern (see below) and storing the details for each website in a YAML file.


module Brandable
  extend ActiveSupport::Concern

  included do
    helper_method :brand


  def brand"config/brands.yml")[request.url])

Then I include it in the ApplicationController so it will be available throughout the project:


class ApplicationController < ActionController::Base
  include Brandable

The brand method returns an OpenStruct object from the data you have in config/brands.yml.

Here is an example of config/brands.yml:

  title: "reinteractive"
  blog_url: ""

  title: "Envisage"
  blog_url: ""

Within any view, you can call either brand.title or brand.address and it is correctly rendered according to the domain you are accessing:


<h1><%= brand.title %></h1>

<%= link_to 'Blog', brand.blog_url %>

4. Customise your CI using the massa gem

When it comes to CI, sometimes you simply want to check only Rubocop and RSpec pass, and other times you want to go the whole way and check erblint, brakeman, and railsbestpractices as well.

Here is an example using travis.yml:

language: ruby
rvm: 2.5.1
sudo: false
cache: bundler

  - postgresql

  chrome: stable
  postgresql: "9.6"

- export TZ=Australia/Sydney
- gem update --system
- gem install bundler

  - bin/setup

  - bundle exec rubocop && bundle exec erblint app/views/**/*.html{+*,}.erb && bundle exec brakeman -Aqz5 && bundle exec rails_best_practices && RAILS_ENV=test bundle exec rspec

If anyone of these fail, the build won't pass. To switch the different tools on or off involves modifying the line bundle exec rubocop && bundle exec erblint app/views/**/*.html{+*,}.erb && bundle exec brakeman -Aqz5 && bundle exec rails_best_practices && RAILS_ENV=test bundle exec rspec over and over again.

I got tired of having to do this, so I have begun working on a gem to manage this more simply. Using the massa gem, you can define a YAML file that will specify all the tools you want:

  description: 'Rubocop'
  command:     'bundle exec rubocop'
  required:    true

  description: 'HAML lint'
  command:     'bundle exec haml-lint app/views'
  required:    true

  description: 'Brakeman (security vulnerability scanner)'
  command:     'bundle exec brakeman -Aqz5'
  required:    true

  description: 'Rails Best Practices'
  command:     'bundle exec rails_best_practices'
  required:    true

  description: 'I18n translations'
  command:     'bundle exec i18n-tasks missing'
  required:    false

  description: 'RSpec'
  command:     'RAILS_ENV=test bundle exec rspec'
  required:    true

You can turn your tools on or off as required, by simply changing required: true to required: false in the config/massa.yml file.

5. Testing your gems against different versions of Ruby/Rails

When you are maintaining a gem, it is a good idea to test it against many different versions of Ruby and Rails. I have combined a couple of things that allow me to maintain my gems with ease.

The first part of the solution comes from Travis: a feature called Build Matrix. When it's set up, it runs specs for each combination of Ruby/Rails/whatever you want to check. If any fails, the build fails.

The second part comes from Thoughtbot: they created an awesome gem called Appraisal (, which integrates with Travis Build Matrix.

Appraisal integrates with bundler and rake to test your library against different versions of dependencies in repeatable scenarios called "appraisals."

The last part is my hack:

Instead of writing a static Appraisals file, I created a dynamic one. This is possible because Appraisals is interpreted as a normal Ruby file.

Here is an example of how I do it in the enumerate_it gem:

require 'net/http'
require 'json'

rails_versions = JSON.parse(Net::HTTP.get(URI('')))
  .group_by { |version| version['number'] }.keys.reject { |key| key =~ /rc|racecar|beta|pre/ }

%w[3.0 3.1 3.2 4.0 4.1 4.2 5.0 5.1 5.2].each do |version|
  appraise "rails_#{version}" do
    current_version = rails_versions
      .select { |key| key.match(/\A#{version}/) }
      .sort { |a, b| <=> }

    gem 'activesupport', "~> #{current_version}"
    gem 'activerecord',  "~> #{current_version}"

    gem 'sqlite3'

Latest Articles by Our Team

Our expert team of designers and developers love what the do and enjoy sharing their knowledge with the world.

We Hire Only the Best

reinteractive is Australia’s largest dedicated Ruby on Rails development company. We don’t cut corners and we know what we are doing.

We are an organisation made up of amazing individuals and we take pride in our team. We are 100% remote work enabling us to choose the best talent no matter which part of the country they live in. reinteractive is dedicated to making it a great place for any developer to work.

Free Community Workshops

We created the Ruby on Rails InstallFest and Ruby on Rails Development Hub to help introduce new people to software development and to help existing developers hone their skills. These workshops provide invaluable mentorship to train developers, addressing key skills shortages in the industry. Software development is a great career choice for all ages and these events help you get started and skilled up.

  • Installfest


    The Ruby on Rails Installfest includes a full setup of your development environment and step-by-step instructions on how to build your first app hosted on Heroku. Over 1,800 attendees to date and counting.

    Learn more about Installfest

  • Development Hub

    Development Hub

    The Ruby on Rails Development Hub is a monthly event where you will get the chance to spend time with our team and others in the community to improve and hone your Ruby on Rails skills.

    Learn more about Development Hub

  • Webinars


    Webinars are our online portal for tips, tricks and lessons learned in everything we do. Make the most of this free resource to help you become a better developer.

    Learn more about webinars

Next Community Events

Find more events

Get the “reinteractive Review” Monthly Email