Gem Patterns

I’ve created a few Ruby gems over the years, and there are a number of patterns I’ve found myself repeating that I wanted to share. I didn’t invent them, but have long forgotten where I first saw them. They are:

Let’s dig into each of them. In the examples, the gem is called hello.

Rails Migrations

Create a template in lib/generators/hello/templates/

class <%= migration_class_name %> < ActiveRecord::Migration<%= migration_version %>
  def change
    # your migration

The .tt extension denotes Thor template. Thor is what Rails uses under the hood.

Add lib/generators/hello/install_generator.rb

require "rails/generators/active_record"

module Hello
  module Generators
    class InstallGenerator < Rails::Generators::Base
      include ActiveRecord::Generators::Migration
      source_root File.join(__dir__, "templates")

      def copy_migration
        migration_template "migration.rb", "db/migrate/install_hello.rb", migration_version: migration_version

      def migration_version

This lets you run:

rails generate hello:install

Change the generator path and class name to match your gem. They must match exactly what Rails expects to work.


Rails Dependencies

If your gem depends on Rails, add railties and any other Rails libraries it needs.

spec.add_dependency "railties", ">= 5"
spec.add_dependency "activerecord", ">= 5"

I typically require a supported version of Rails.

In code, don’t require Rails gems directly, as this can cause them to load early and introduce issues.

require "active_record" # bad!!


Instead, do:

require "active_support"

ActiveSupport.on_load(:active_record) do
  include Hello::Model


Testing Against Multiple Dependency Versions

If your gem has dependencies, you may want to test against multiple versions of a dependency. For instance, you may want to test against multiple versions of Active Record.

To do this, create a test/gemfiles directory (or spec/gemfiles if you use RSpec).

Create test/gemfiles/activerecord50.gemfile with:

source ""

gemspec path: "../../"

gem "activerecord", "~> 5.0.0"

Install with:

BUNDLE_GEMFILE=test/gemfiles/activerecord50.gemfile bundle install

And run with:

BUNDLE_GEMFILE=test/gemfiles/activerecord50.gemfile bundle exec rake


On Travis CI, you can add to .travis.yml:

  - Gemfile
  - test/gemfiles/activerecord50.gemfile

You can also use a library like Appraisal to help generate and run these files.

Testing Against Rails

To test against Rails, use a library like Combustion. It’s designed to be used with RSpec, but I haven’t had any issues with Minitest. Combustion generates some files that aren’t needed, so I just delete them.

Combustion.initialize! :all


Coding Your Gemspec

There are a variety of ways to code your gemspec. Here’s the one I like to use:

require_relative "lib/hello/version" do |spec|          = "hello"
  spec.version       = Hello::VERSION
  spec.summary       = "Hello world"
  spec.homepage      = ""
  spec.license       = "MIT"        = "Your Name"         = ""

  spec.files         = Dir["*.{md,txt}", "{lib}/**/*"]
  spec.require_path  = "lib"

  spec.required_ruby_version = ">= 2.4"

  spec.add_dependency "activesupport", ">= 5"

  spec.add_development_dependency "bundler"
  spec.add_development_dependency "rake"

Change files if your gem has app, config, or vendor directories. I typically use the last supported version for the minimum Ruby version.

If your gem has an executable file, add:

spec.bindir        = "exe"
spec.executables   = ["hello"]

Don’t check in Gemfile.lock.

Some gems have moved development dependencies entirely out of the gemspec and into the Gemfile, which is another option.


You’ve now seen five patterns that can be useful for Ruby gems. Now go build something awesome!

Published August 2, 2019

You might also enjoy


Bulk Upsert in Ruby/Rails

New Rails App Checklist

All code examples are public domain.
Use them however you’d like (licensed under CC0).