This is Anti-pattern—thoughts on programming and whatnot by Brandon Weiss.


February 24th, 2015

I don’t always install the Rails gem globally, but when I do, I cry myself to sleep at night. —Me

Ruby gems fall into one of two categories based on how you install them. There are the gems you install globally, outside the context of an application, like Bundler or Pry. And then there are the gems you install locally, inside the context of an application, like Faraday or BCrypt. But then there’s Rails.

Rails is an application dependency so it should be installed locally with Bundler. But the Rails gem is also used to generate the skeleton of the application, which includes the Gemfile that Bundler uses in order to install Rails locally. It’s a bit chicken and the egg.

You’re probably wondering why that even matters. You just install the Rails gem globally.

$ gem install rails
Fetching: thread_safe-0.3.4.gem (100%)
Successfully installed thread_safe-0.3.4
Fetching: minitest-5.4.2.gem (100%)
Successfully installed minitest-5.4.2
Fetching: tzinfo-1.2.2.gem (100%)
Successfully installed tzinfo-1.2.2
Fetching: i18n-0.7.0.beta1.gem (100%)
Successfully installed i18n-0.7.0.beta1
Fetching: activesupport-4.1.6.gem (100%)
Successfully installed activesupport-4.1.6
Fetching: erubis-2.7.0.gem (100%)
Successfully installed erubis-2.7.0
Fetching: builder-3.2.2.gem (100%)
Successfully installed builder-3.2.2
Fetching: actionview-4.1.6.gem (100%)
Successfully installed actionview-4.1.6
Fetching: rack-1.5.2.gem (100%)
Successfully installed rack-1.5.2
Fetching: rack-test-0.6.2.gem (100%)
Successfully installed rack-test-0.6.2
Fetching: actionpack-4.1.6.gem (100%)
Successfully installed actionpack-4.1.6
Fetching: activemodel-4.1.6.gem (100%)
Successfully installed activemodel-4.1.6
Fetching: arel- (100%)
Successfully installed arel-
Fetching: activerecord-4.1.6.gem (100%)
Successfully installed activerecord-4.1.6
Fetching: mime-types-2.4.3.gem (100%)
Successfully installed mime-types-2.4.3
Fetching: mail-2.6.1.gem (100%)
Successfully installed mail-2.6.1
Fetching: actionmailer-4.1.6.gem (100%)
Successfully installed actionmailer-4.1.6
Fetching: thor-0.19.1.gem (100%)
Successfully installed thor-0.19.1
Fetching: railties-4.1.6.gem (100%)
Successfully installed railties-4.1.6
Fetching: sprockets-3.0.0.beta.2.gem (100%)
Successfully installed sprockets-3.0.0.beta.2
Fetching: sprockets-rails-2.2.0.gem (100%)
Successfully installed sprockets-rails-2.2.0
Fetching: rails-4.1.6.gem (100%)
Successfully installed rails-4.1.6
22 gems installed

Because Rails has a ton of dependencies and installing it globally makes an absolute mess of your gem list. It completely obscures any relevant information you might be trying to find in there. And good luck uninstalling it; you’re going to have to manually uninstall each dependency.

I realize this is definitely a nit, but it bothers me to no end. You don’t need Rails globally except to generate new app skeletons.

I thought I’d be clever and install Rails with --ignore-dependencies, but it turns out the Rails binary isn’t even in the Rails gem, it’s in the Railties gem. I tried installing the Railties gem without dependencies, but it turns out the logic for generating a Rails skeleton is spread throughout a bunch of dependencies.

So I whipped up a simple gem called Railyard. It sandboxes Rails, installing it locally inside the gem, on demand. You can use it to switch to any Rails version you like and generate a Rails skeleton for it, without having to install Rails globally.

$ gem install railyard
Fetching: thor-0.19.1.gem (100%)
Successfully installed thor-0.19.1
Fetching: railyard-0.1.0.gem (100%)
Successfully installed railyard-0.1.0
2 gems installed
$ railyard new next_big_thing

Ah, that’s so much better.