Get Your Own Free Private Gem Server

Using Heroku you can privately host your gems in just a couple of minutes. Here’s how.

Start by creating an empty project folder, and add a Gemfile with only the source and ruby version:

1 # File: Gemfile
2 source 'https://rubygems.org'
3 ruby '2.0.0'

Then run bundle to generate Gemfile.lock.

Next, create a Procfile with the following content:

1 # File: Procfile
2 web: gem server -p $PORT

Then set up Git:

1 $ git init .
2 $ git add .
3 $ git commit -m Initial commit

Create a new Heroku app and push your application to Heroku:

1 $ heroku create
2 $ git push heroku master

Then launch your new privately hosted gem server in the browser:

1 $ heroku open

And just like that you have your very own private gem server. Now let’s push a gem to the server.

First you’ll want to create a .gitignore file and add .bundle to it so we don’t end up pushing our local Bundler settings to heroku:

1 $ echo ".bundle" >> .gitignore
2 $ git add .gitignore
3 $ git commit -m Ignoring the .bundle path

Next you’ll need a vendor/cache folder. This is where you’ll place your private .gem files. So go ahead and create that folder now, and copy your gem file into it.

1 $ mkdir vendor
2 $ mkdir vendor/cache
3 $ cp my.gem vendor/cache # replace 'my.gem' with your actual gem file

This is where things can get a little tricky. In order for us to push our gem to Heroku, we need to first run bundle install. However since our gem is going to be privately hosted, Bundler will try and fail to download it from rubygems.org. So we need to cache the gem first so it doesn’t try to download it. Ironically, the way we do that is by using the --no-cache flag. Then you’ll need to run bundle package --all to vendor your gem’s dependencies along with the gem:

1 $ bundle install --no-cache
2 $ bundle package --all

Using bundle --no-cache tells Bundler that the .gem files have already been copied into the vendor/cache folder, and it will install those instead of connecting to rubygems.org. bundle package --all downloads the missing dependencies and copies their .gem files into the vendor/cache folder, thus completing the installation.

It’s a bit confusing, but in the end it’s really only this three step process:

  • Copy your private gem’s .gem file into vendor/cache
  • Run bundle install --no-cache
  • Run bundle package --all

Then of course you’ll need to push those files to Heroku:

1 $ git add .
2 $ git commit -m Installed my private gem
3 $ git push heroku master

Refresh your browser, and you’ll notice that your gem will now be listed.

Now all you have to do to install the private gem in your application is add the URL to your Heroku app that’s hosting the gems to your Gemfile. For example:

1 # File myapp/Gemfile
2 source 'https://rubygems.org'
3 source 'http://private-gem-server.herokuapp.com'
4 
5 gem 'my_private_app'

How to Create A Swap File without a Partition

So this will be a very short article, but it is something I find very useful from time-to-time, especially when compiling code on a cheap cloud server with very limited resources. Here’s how to enable a temporary swap file without having to have a partition dedicated to it:

1 sudo dd if=/dev/zero of=/swap bs=1M count=2048
2 sudo mkswap /swap
3 sudo swapon /swap

And that’s it! Just change the 2048 in count=2048 to however many kilobytes you’d like the swap file to be.

A Simple Rails CMS

If you’re building a website, you’re no doubt going to want to add some dynamic content to it. In Ruby on Rails, this is a surprisingly easy task and can be set up in just a few minutes. No gems required.

To get started, first set up a Contents model:

rails g contents slug:string format:string title:string author:string body:text

Then modify the migration file that was created so it includes a default value for :format and has a unique index for :slug:

 1 # File: db/migrate/*_create_contents.rb
 2 
 3 class CreateContents < ActiveRecord::Migration
 4   def change
 5     create_table :contents do |t|
 6       t.string  :slug
 7       t.string  :format, default: "html"
 8       t.string  :title
 9       t.string  :author
10       t.text    :body
11       t.timestamps
12     end
13 
14     add_index :contents, :slug, unique: true
15   end
16 end

Now configure the Content model so it parameterizes the title into a slug, which is what we’ll be using for the URL to display the content. You’ll also need to set up the accessible fields, and validations:

 1 # File: app/models/content.rb
 2 
 3 class Content < ActiveRecord::Base
 4   attr_accessible               :title,
 5                                 :body,
 6                                 :author,
 7                                 :format
 8 
 9   validates_presence_of         :title,
10                                 :format,
11                                 :slug
12 
13   before_validation do
14     self.slug = self.title.parameterize
15   end
16 
17   def to_param
18     self.slug
19   end
20 end

Next create a controller that will render the requested Content:

 1 # File: app/controllers/contents_controller.rb
 2 
 3 class ContentsController < ApplicationController
 4   def show
 5     # Get the ID of the page being requested, defaulting to 'home'
 6     @id = params.fetch(:id, 'home')
 7 
 8     # Get the format of the requested content
 9     @format = params.fetch(:format, 'html')
10 
11     # Find the content by its slug and format
12     @content = Content.find_by_slug_and_format!(@id, @format)
13 
14     # Render the content inline
15     render inline: @content.body
16   end
17 end

Configure your app’s routes:

1 # File: config/routes.rb
2 
3 MyApp::Application.routes.draw do
4   root to: "contents#show"
5   get "contents/*id" => "contents#show"
6 end

Fire up the rails console and create some default content:

1 Content.create! format: 'html', title: 'Home Page', body: '<h1><%= @content.title %></h1>'

Now when you visit your app in the browser you’ll be presented with content that was pulled from the database and rendered by your application.

This is just a very brief example of how to set this up. There’s a lot more to take into consideration. For example, since you can execute ERB code in your site’s dynamic content using this method, you’ll need to take the necessary security measures in the controller to ensure that malicious code or rouge scripts could not be executed. Which means that, unless you are the only person who will be editing your site’s content, you will probably want to use something other than Rails default template renderer, such as Shopify’s Liquid template language, since it leaves your site open to too many vulnerabilities otherwise.

You’ll also need to set up the controller to edit the content from within the browser. I left that out of the above example for the sake of brevity, since it is very basic Rails code.

ActiveRecord::Session::Store

Recently I ran into a cookie overflow issue when using the Sidekiq gem for background processing. To solve the issue, I had to abandon using cookies for session storage, and instead use the database for sessions. It’s very easy to set up, and the instructions can be found in any Rails app in the config/initializers/session_store.rb file.

Something that isn’t outlined in the initializer, however, is that if you also create a Session model, but instead of descending from ActiveRecord::Base, descend from ActiveRecord::Session::Store, you can access your app’s sessions from anywhere in your application:

1 # File: app/models/session.rb
2 class Session < ActiveRecord::Session::Store; end

The Session object will behave like any other ActiveRecord model, with the exception of the #data method, which will return a Hash object.

Here’s an example of how you could use this to broadcast a message to all your site’s current visitors:

1 Session.all.each do |session|
2   session.data['flash'] ||= ActionDispatch::Flash::FlashHash.new
3   session.data['flash'][:alert] = 'Server going down in 10 minutes for scheduled maintenance.'
4   session.save!
5 end

You could even use it to display random site promotions. For example, using the clockwork gem, you could do this:

 1 # File: lib/promotions.rb
 2 require 'clockwork'
 3 require 'config/boot'
 4 require 'config/environment'
 5 
 6 every(1.minute, 'random.promos') do
 7   Session.all.each do |session|
 8     promo = Promo.all.sample
 9 
10     session['flash'] ||= ActionDispatch::Flash::FlashHash.new
11     session['flash'][:promo] = promo.call_to_action
12     session.save!
13   end
14 end
1 # File: app/views/application.html.erb
2 <% if flash[:promo].present? %>
3   <div id="promo"><%= raw flash[:promo] %></div>
4 <% end %>

Now the next time your site’s current visitors visit a new page they’ll be presented with the promotion, while any new visitors won’t see any promos until they’ve been browsing your site for at least 1 minute.

Multiple Route Files in Rails

Lately I have been working on a Rails project with routes that have been getting more and more complicated. The project has three different user types. Each user has routes that are only visible when they’re signed in, plus public routes, with some that are only visible when certain users are signed in, and some of the routes are repeated under different namespaces, or with different constraints.

Since the routes file has been expanding over time, I decided that it would be best to split it up into smaller, easier to read and manage files. After doing a search on multiple rails route files to find out how to configure my application for this, I found this simple one line solution that you can add to your config/application.rb file in a Rails 3.2 or higher application:

1 config.paths["config/routes"] += Dir[Rails.root.join("config", "routes", "*.rb")]

What that does is tell your application to use any file located in config/routes as a routing file.

However, there were a couple of drawbacks I found in using this method. First, since config/application.rb is only loaded once when your application boots, if you were to add, rename, or delete any files in the config/routes directory, you would need to restart your application for the changes to become effective.

But the biggest issue, and the reason I chose not to use this method, is that it does not allow you to specify the order in which the routes are loaded. And for the application I’m working on the routes need to be loaded in a specific order.

So I ended up having to write my own method of using multiple route files, which is in the form of a very simple routing extension that looks like this:

 1 # File: config/initializers/routing_extensions.rb
 2 class ActionDispatch::Routing::Mapper
 3   def draw(*names)
 4     names.each do |name|
 5       file = Rails.root.join("config", "routes", "#{name.to_s}.rb")
 6       code = File.read(file)
 7       eval(code)
 8     end
 9   end
10 end

Now I can specify the exact order the external route files should be loaded in, when the routes should be loaded, and even use them more than once. For example, here is a very small portion of the routes in the application I am working on right now:

 1 # File: config/routes.rb
 2 AppName::Application.routes.draw do
 3   devise_for :admin, :user
 4 
 5   authenticated(:user) { draw :authenticated }
 6 
 7   authenticated(:admin) do
 8     namespace(:admin) { draw :authenticated }
 9   end
10 
11   draw :public
12 end
1 # File: config/routes/authenticated.rb
2 resource :dashboard, :only => [:show]
3 resource :preferences, :only => [:edit, :update]
4 root :to => "dashboards#show"
1 # File: config/routes/public.rb
2 get "/about" => "about#show"
3 root :to => "about#show"