Extracting a Gem from your Rails app

ConFoo Vancouver 2017


So you got that big pile of useful code.

Benefits of extracting

open-source code

  • Will simplify your actual codebase
  • Can bring collaborators
  • Fresh and new ideas
  • Useful code for future and parallel projects
  • Reduce your test suite size
  • Give back to the community

First gem?

  • You already know the requirements and edge cases
  • The implementation already exists
  • You already have an app to test it
  • Focus on the interface

Where to find useful code to extract?

About anywhere!


Are you solving common problems?
Have some cool scripts?

Where to find useful code to extract?

  • Custom validations
  • Test matchers
  • Wrapper around an external API
  • Additions or changes to Rails
  • PORO modeling common things
  • And many more!

This talk is a step by step guide to extract a gem from existing code

Step 1:

Identify and move the key parts of your code.

Problem solved



Step 2: 

Refactor your code to move as much as possible to lib/


Test in isolation

Break dependencies

Step 3:

Setup of the gem

Bundle gem [gemname]

  • Code of conduct
  • RSpec (minitest available)
  • Travis-CI ready

Rails plugin new [gemname]

  • Dummy rails app
  • Minitest only
  • Rake tasks setup
  • Useful for Rails Engines


Small number of variations Gemspec, licence, readme, etc

I did both commands

# Make dir and git init commands

> cd ..

> bundle gem has_prerequisite

> cd has_prerequisite

> git commit -Am "init the gem"

> cd ..

> rails plugin new has_prerequisite --skip-test --dummy-path=spec/dummy

> cd has_prerequisite

> git add -p

> git commit -m "init the rails specific setup of the gem"


  • Edit the Gemspec with the gems info
  • Tests are running?
  • Online Git repository

Step 4:

Move the code!

Move the tests first

  • Make sure required dev and test dependencies are in the Gemspec (rspec-rails, shoulda-matchers, its, etc)
  • Some minor changes to the test setup are expected
  • Make sure they run
  • Make sure they fail properly

Move the implementation

  • If step 2 was skipped, you might have broken dependencies
  • Add them to the gemfile and require
  • Implement components you don't want to be dependent on


I decided to keep the dependency on Active Support but not Devise.


So I have to implement similar methods


  1) HasPrerequisite redirection it redirects to the path when the prerequisite is not met
     Failure/Error: store_location_for(:user, request.fullpath)
       undefined method `store_location_for' for #<#<Class:0x007f9d98a359e8>:0x007f9d9b931238>
     # ./lib/has_prerequisite.rb:36:in `perform_checks'
     # ./spec/has_prerequisite_spec.rb:43:in `block (2 levels) in <top (required)>'
     # ./spec/has_prerequisite_spec.rb:55:in `block (3 levels) in <top (required)>'


Add features

Refactor again


Hooks for initialisation


  • Extend core classes
  • Initialisers
  • Set generators


module HasPrerequisite
  class Railtie > ::Rails::Railtie
    initializer "has_prerequisite.configure_view_controller" do |app|
      ActiveSupport.on_load :action_controller do
        include HasPrerequisite

Step 5:

Test locally

Test again?

  • yes.
  • Integration test (I have a dummy app!)
  • Pack the gem locally
  • Reference it from your application


gem 'has_prerequisite', path: '~/dev/has_prerequisite'
> bundle install
=> It will use your gem 

> rspec

Note: If you changed the interface, you'll have to change the usage and maybe some tests

Step 6:


Version number

I recommend following Semantic Versioning


Version number

  • Production ready?
  • Stable API?

When to publish 1.0.0 ?


Tip: you can always use the labels (1.0.0.beta, 1.0.0.rc.1, 1.0.0.pre, 1.0.0.racecar-1)



Code of conduct


Use Git/Github features

  • Readme for documentation
  • Push hooks to test
  • Issue tracker
  • Projects
  • Releases automatically tagged
  • Use branches to merge and deploy bugfixes across versions


  • Where gems magically come from
  • Create an account

Private servers

  • Run your own with `gem server`

  • Gemfurry

  • Note: configure .gemspec to avoid accidental pushes to Rubygems.org


→ bundle exec rake release   
has_prerequisite 1.0.0.alpha built to pkg/has_prerequisite-1.0.0.alpha.gem.
Tagged v1.0.0.alpha.
Pushed git commits and tags.
Pushed has_prerequisite 1.0.0.alpha to rubygems.org.

Step 6:


Step 6:



New features

Pull requests

Never forget about the documentation

Open-Source Starter Kit

  • CI servers
  • Contributing guides
  • Set expectations on PR
  • Use automated review tools
  • Build a team you trust


  • Those pull-requests can wait
  • Those bugs can wait
  • Delegate! Delegate!
  • Your free time is YOURS
  • You don't owe anyone anything

Free Time management

Don't burn out

Enjoy it

Step 7:


Thank you! ❤️💎


Useful links