Chapter 21

Deployment: Publishing Engines

Now that your engines are packaged as gems, and versioned, they can easily be loaded in your application using Bundle. But if we want Bundle to find them, they need to be available from somewhere online!

How do we do that?

21.1. Public vs Private

To push your gems online, you have two solutions: Public and Private. Your choice really depends on what kind of work you are doing, and if you are working on an open-source engine or on an engine that’s supposed to stay private.

21.1.1. Public? RubyGems!

If you want to share your engine with the world, your life will be easy as pie. That’s what karma is all about, right? If you are ready to share it, you can just use RubyGems. That’s it!

RubyGems stores all gems for free, and you can upload yours there too. Anyone will be able to use it and see your code, so if that’s not a problem for you, go for it!

Unfortunately, sharing your gems is not always possible. Even if you want to, you might not have permission to share your code. The corporate world doesn’t like it when you share their secrets! That’s understandable, so we need another solution… but don’t expect it to be free (it’s fine, the company will pay…).

21.1.2. Private? Pick one

Lucky us… if RubyGems can do it, why can’t we? Other people have thought about this too, and that’s probably how Gemfury was born.

Gemfury gives you a gem server where you can store private and public gems, and you control if you want a gem to be public or remain private. Unfortunately, Gemfury is not free; you pay per user for any private gems.

  • Make Your Own

So if Gemfury is too pricey for you, how about making our own? It will have a cost too, but it is going to be a small flat fee. The only thing we will need is a server. Any cheap provider like Digital Ocean or Linode will do. The server will just store packaged gems and send them when someone runs the bundle install command. Nothing too intense. All we need is for it to be accessible remotely.

Got a server? Good! But we still have to set up a gem server. The good news is that some people have created useful gems that we can use to set up a gem server (irony at its best). We will show you how to build a private gem server with Gem in a Box on a Digital Ocean Droplet. You can get a server and follow the steps, but honestly, it’s not that hard, so reading should be enough to understand how it works.

You can use any server that you have access to. If you want to get your own Digital Ocean Droplet, you can sign up here. This is an affiliate link and you will get a credit of $10 if you use it. This means you can try building your private gem server for free! (Devblast will also get a commission if you become a regular user.)

Let’s get started!

21.2. A private home for your engines

21.2.1. Setting up Geminabox

Thanks to this neat little gem, Gem in a Box, we can easily create a simple gem server. The following commands will be run from a Digital Ocean Droplet, and we will use RVM to install Ruby. We will put the Gem in a Box web application in /var/www/gemserver and store the actual gems in /var/devblast/gems/ (Don’t forget that this is our personal server and nobody else has access to it).

Step 2: Download RVM and Ruby

\curl -sSL https://get.rvm.io | bash -s stable --ruby

Step 4: Load RVM

source ~/.rvm/scripts/rvm

Step 6: Install Geminabox

gem install geminabox --no-doc

Step 8: Create a folder to store the gems

mkdir home/your_folder/gems

Step 9: Create & update /var/www/gemserver/config.ru

Create /var/www/gemserver/config.ru by running

touch /var/www/gemserver/config.ru

and populate it with the contents of Listing 1. Don’t forget to change A_VERY_SECRET_KEY to something very secret.

Listing 0.1: Contents of config.ru file /var/www/gemserver/config.ru
require "rubygems"
require "geminabox"

Geminabox.data = "/home/your_folder/gems" # ... or wherever

use Rack::Auth::Basic, "Blast Secret Gem Server" do |username, password|
  username == 'blast' && password == 'A_VERY_SECRET_KEY'
end

run Geminabox::Server

If you want to keep your server open, you can remove HTTP authentication by removing these lines:

use Rack::Auth::Basic, "Blast Secret Gem Server" do |username, password|
 username == 'blast' && password == 'A_VERY_SECRET_KEY'
end

Step 10: Fix the permissions

sudo chown -R www-data:www-data /var/www/gemserver

Step 11: Install a web server

We’re using Puma because we like it and because Rails has now made it the default.

gem install puma

Step 12: Start Puma as a daemon

Before running the command below, be sure that you are in the /var/www/gemserver we created earlier. Then just launch the server:

puma --port 9292 config.ru -d

If you want to have more details about what’s going on with puma while running it, just don’t run the server as a daemon and remove the -d parameter. It can be useful to debug any issues present in our config.ru.

Step 13: Access our gem server

And that’s it, we’ve got ourselves a private gem server!

https://s3.amazonaws.com/devblast-modr-book/images/figures/05_21/initial_geminabox
Figure 1

21.2.2. Pushing gems to your private gem server

So how do we push gems now? Let’s push the Core module to see how it works. The following commands can be run from your local computer.

First, navigate to blast_crm/engines/core.

Step 1: Encapsulate the Core in a gem

gem build blast_core.gemspec

Step 2: Configure Geminabox

Set the remote host for Geminabox:

gem inabox -c

Step 3: Push the gem

gem inabox blast_core-0.0.1.gem

On your gem server you can check the presence of the gem in the folder you have configured via the Geminabox.data variable in the config.ru file. Just have a look at the folder and our blast_core-0.0.1 should be present!

Step 4: Remove the local gem

rm blast_core-0.0.1.gem

And that’s it! Our gems are on our private gem server.

Step 5: Add your Gem Server to your default sources

Adding the source to the default sources will allow us to query for our gems from anywhere on your computer.

gem sources -a http://blast:A_VERY_SECRET_KEY@[your_server]:9292/

You can use the gem sources command to see all the sources listed, the one we added is now included in this one.

Step 6: Try to install blast_core

gem install blast_core

And you should see an output that shows you that your gem was installed.

21.2.3. Bundle install your gems

We just added our gem server as a source for the rubygems gem. Now, let’s see how we can load gems in your Rails application using Bundle.

Step 1: Add your Gem server as a source to your application Gemfile

Listing 0.2: Gemfile using private gem server Gemfile
source "https://rubygems.org"
source "http://blast:A_VERY_SECRET_KEY@[your_server]:9292"
.
.
.

Step 2: Secure your secret key

Rails 5.2 gives us an amazing little tool called credentials to securely store various secret keys. To use it we will need to update it (you can use any editor your like) by running the following command:

EDITOR=vi rails credentials:edit

Now simply add the following line at the bottom of the file:

gem_server_key: A_VERY_SECRET_KEY

Finally, tell your Gemfile to look for your key in the credentials file:

Listing 0.3: Updated Gemfile using Credentials Gemfile
source "https://rubygems.org"
source "http://blast:#{Rails.application.credentials.gem_server_key}@blast.com:9292"
.
.
.

Step 5: Use the new gem

Remove the path option for the Core module inside your Gemfile, and add the gem:

Listing 0.4: Gemfile that uses Core gem Gemfile
.
.
.
gem 'blast_core'

Step 7: It works!

You should see your usual bundle output that includes our gem.

21.2.4. Pushing all our modules

Now that our private Gem server is ready, it’s time to push our modules! But first, let’s update the versions. We’re going to update all our modules to 1.0.0 and officially release them! Do the four following steps for each module: Core, Contacts and Tasks and replace {module} with the appropriate module name.

Step 1: Change version

Listing 0.5: Updating module version blast_crm/engines/{module}/lib/blast/{module}/version.rb
module Blast
  module Core
    VERSION = '1.0.0'
  end
end

Step 2: Create the gem

gem build blast_{module}.gemspec

Step 3: Push the gem

gem inabox blast_{module}-1.0.0.gem

Step 4: Remove the local gem

rm blast_{module}-1.0.0.gem

21.3. Wrap Up

In this chapter we learned about where to publish our engines and use the published gems in our production application.

21.3.1. Next Step

Next, we will learn how to create our own gem server.