Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Link: Ore, when 'bundle gem' isn't cutting it.

I often write small gems to encapsulate libraries, and I always want them set up in a particular way, especially with the inclusion of rspec and a test skeleton.

To date I’ve been using a template repository then running through with search and replace.

Read more »

The Healthy Gemfile

Often when working on ruby projects that use Bundler, I see Gemfiles that look like this:

gem 'rails',          '3.0.15'
gem 'rest-client',    '1.3.0'
gem 'subexec',        '0.0.4'
gem 'uuidtools',      '2.1.1'

The string on the right hand side of each gem specification is a fixed version specification. If you ask bundler to update any of these gems, it will make a bit of noise but those gems listed will essentially stay the same.

The typical reason for structure a Gemfile like this is to prevent changes in dependent software from causing compatibility issues or to reduce the chance of bugs or unexpected behaviour.

This strategy is problematic for several reasons: it keeps your project stale, makes it difficult to maintain overall project security and worse yet, can provide a false sense of security. There is a much better and simpler way of writing a Gemfile that will preserve the health and consistency of your dependencies.

Problems with this approach

The first and most obvious problem is that your application will quickly become out of date. The Ruby community moves very quickly and introduces changes quite frequently which means that if you freeze your gems, you may find it very difficult to upgrade later. This problem can be compounded when a security patch is made and the version of the gem you're using is no longer supported.

A more subtle problem is that the gems listed in your Gemfile have dependencies, and those dependencies may not necessarily be required with as strict a version specification. If you do a bundle update, some of those dependencies could change and break your application.

If you're the more conservative type, and you're developing an application that might be in use for some time, you may also be aware that the gems you depend on might not be available forever. They could be removed from the repository, or even altered in a way that breaks your app. If this concerns you there is a much better solution.

A better way of managing your gems

Use Gemfile.lock to document required versions

The true manifest of gem versions is the file Gemfile.lock which is updated by bundler any time your gemset is changed. This should be kept in source control, so that whenever you or your collaborators run bundler install, the exact versions of every gem are installed.

Document dependency problems

If a particular gem version breaks your project, by introducing a bug or a change to it's API, lock it using the appropriate modifier.

Typically an API change is only introduced in a major version change (e.g: 3.x.x becomes 4.x.x). You can make sure your gem stays reasonably up to date but doesn't change to the next major revision using a pessimistic restriction like so: '~> 3.1.1'.

If the next minor version introduces a bug which breaks your project, lock the gem version with a specific revision (e.g '3.1.1').

Whenever you restrict a gem version, document why! Sometimes the errors causes by a dependency change can be quite obscure and waste significant time. I like to leave a comment like so:

# TODO: Remove version lock when this bug
# is fixed. It breaks the transmogrification adaptor because of a missing method.
gem 'descartes', '3.1.1'

Use tests to drive out dependency issues

The best indication that a gem has broken your project or needs to be managed more carefully is a test suite with good coverage. With good coverage, particularly integrations tests you can be confident that whenever you do a bundle update everything still works.

If your gems are kept up to date most of the time and you use source control it will be quickly obvious which version changes introduced a bug.

Be hesitant to specify a version restriction

And finally, don't specify a version restriction in your Gemfile without a very specific and well understood reason. It can often be tempting to simply list the version of the gem available at the time or to lock the version if you come from a more conservative background. A healthy Gemfile has few version restrictions, explains clearly the ones it has and comes attached with a lockfile for quick deployment and development.

[Standup][sf] 5/20/2011 DVORAK? I hardly knew her!


"Can I use after_initialize to set up nested associations for use with Controller#new actions?"

Not recommended. It is better to write a custom #new_for_form method in your model that pre-populates your instance variables with the 1 or more nested objects. That way you can test drive it, too.

"DelayedJob YAML parser in Ruby 1.9 is having issues."

The compiled-in psych library has issues, use the tenderlove/psych gem instead. You have to use Bundler, however. Invoking require "psych" will use the compiled-in version.

"RubyMine is not honoring a DVORAK keyboard layout properly (it is mapping keyboard shortcuts to the QWERTY layout)"

Use a hardware dongle.

"Jenkins is trying to kill off Postgres?"

Does anyone have Jenkins CI working with Postgres? It seems that after a build is complete, some java deep down inside Hudson is trying to parse the process table, and it is choking on the Postgres entries. (Postgres re-writes ARGV[0] to display status info, you can't rely on it be the original command line.) It remains a mystery why Jenkins would even need this information.

"Is anyone using Chrome in CI? The windows are transparent"

Sounds pretty. Odd, but pretty.


"brew info ... is your friend"

Can't remember how to start or stop a daemon under OS X? If you installed it via Homebrew you are in luck:

brew info <foo>

Will print out the original install instructions, including exact lines to pass to launchctl(1), etc.

"More 'special' keywords to avoid in your models: target and source"

ActiveRecord Polymorphic Associations use a method called target internally. If you have an attribute in your model / database, also called target, then strange things will happen.

"Paperclip's <model>.attachment.exists? is slow; it goes out to S3 (or whatever the store is)"

And it happens in strange places. Be warned. Or mock out your network calls.

SF Standup 5/6/2011: Bundler Blah Blah Blah Blah

Interesting Things

  • A certain Pivotal project runs 'bundle update' often, since they have a shared gem that gets updated a lot. They were wondering why it was so slow, and supposed it was due to slowness at, and thought a local mirror would help. They were wrong. Turns out the slowness is in the implementation of rubygems, whereby a 110K list of gems is marshalled and unmarshalled.

Standup 2010-11-18


  • Bundler + Heroku gotcha: Deploys to Heroku can break if you are using Bundler v1.0.6 in your local development environment (as of this writing, Heroku is using v1.0.3). Apparently the --deployment switch is being stripped off and Gemfile.lock is rebuilt. If the file differs from what's in the git repository, the deploy will fail with a somewhat mysterious error message. Work-around: Specify the bundler gem version to v1.0.3 (perhaps even up to v1.0.5) in your Gemfile.

Standup 2010-11-17

Interesting Things

  • nginx may write temporary files to local disk, especially for large files (>64K). You should make sure that proxy_temp_path is writable. You can also control the size when this happens by adjusting proxy_temp_file_write_size. The more interesting thing is that if the directory is not writable, you won't see an error message in the logs, but strace is still your friend.


"Should I include Gemfile.lock in a repository for a gem?"

  • Yes, but don't include it in the gemspec, that way it won't be distributed with the gem.
  • Bundler doesn't look at lock files in dependent gems anyway.
  • It makes less sense for a gem since you wouldn't want to lock down the environment for all of your gem's users.

"What library should I use for GUIDs?"

  • uuidtools
  • universally unique identifiers may have trouble in other universes, please use caution when crossing these boundaries ;-)

Standup 11/5/2010: Happy Friday Edition


  • bundle install --without test excludes the test group in your Gemfile from the install. It works well for reducing the size of your Heroku slug. However, there's a glitch with this option on Heroku -- when you specify it, Heroku reinstalls every included gem every time you deploy. It does respect your Gemfile.lock, so you're trading a smaller slug for a longer deploy.

  • Pivotal's open source CIMonitor project now supports OpenID! Thanks Tyler and Josh.

  • Arel has a bug that makes it difficult to use in rails console. Every time you add a predicate, the number of internal objects in the Arel result increases exponentially. So, by the time you have 5 or 6 predicates, the console finishes generating the expression more or less instantly, and then spends 15+ minutes calling to_s on the resulting Arel object in order to display it to you. tl;dr: when you're playing with Arel in rails console, end every line with ; nil to avoid having it print out the result. The exponential object explosion will be fixed in Rails 3.1.

Oh look a parade!


Do people put bundler in the Gemfile?

Yes. Bundler is smart enough to omit it from the cache. It does, however, still follow the rules for version. We recommend using ~> 1.0.0 as the version string, because 1.x is supposed to be backwards-compatible with the current Gemfile format.

If you instead use = 1.0.0 and your managed hosting environment updates bundler to something more recent, things will ASPLODE.


  • Tech talk that was going to be today has moved to Thursday, due mostly to noise concerns. See you tomorrow.

Standup 08/05/2010: ‘bundle check’ and Websockets

Ask for Help

  • How to specify compile flags when installing the mysql gem with Bundler 1.0.0RC1?

Don't. Instead use version 2.8.1 of the mysql gem and ensure mysql_config is on your PATH.

Interesting Things

This saved about three minutes of build time (from what used to be 11ish runs of bundle install instead of bundle check.)

  • Websocksets are easy, use them if you need to 'push' to your webapp and your server can handle many persistent connections.

This was in reaction to some recent conversation between Pivots about Pusher, which will keep persistent connections on your behalf.

This said, here's a quote from

WebSockets represent an alternative to Comet and Ajax. However, each technology has its own unique capabilities. Learn how these technologies vary so you can make the right choice.

Automating Bundler In Your Deploy

If you are using Bundler to lock and package your gem dependencies in your app (which you should), here's some tips on making everything automatic in your Capistrano deploy.

Refer to the Bundler Documentation for instructions on how to use Bundler to properly package your gems and check everything in.

Once this is done, however, you still must ensure that two things are done on every machine to which you will deploy:

  1. Bundler is installed
  2. You run 'bundle install' on every deploy to install the packaged gems on the local machine (and compile any gems with native dependencies)

Here's the Capistrano magic to accomplish these two tasks automatically on every deploy:

before "deploy:bundle_install", "deploy:install_bundler"
after "deploy:update_code", "deploy:bundle_install"

namespace :deploy do
  desc "installs Bundler if it is not already installed"
  task :install_bundler, :roles => :app do
    sudo "sh -c 'if [ -z `which bundle` ]; then echo Installing Bundler; sudo gem install bundler; fi'"

  desc "run 'bundle install' to install Bundler's packaged gems for the current deploy"
  task :bundle_install, :roles => :app do
    run "cd #{release_path} && bundle install"

Oh, and for you GemInstaller users out there - here's an easy way to generate a Bundler Gemfile from your geminstaller.yml config:

geminstaller --bundler-export > Gemfile

You'll probably still need some tweaks, but this will get you started. Just make sure you upgrade to GemInstaller 0.5.5 first (0.5.4 forgot to put the 'source' line in the Gemfile).

Happy Bundling! -- Chad

P.S. There is a similar article here, which includes tasks to symlink your .bundle dir into the Capistrano shared directory, but my deploy was pretty fast anyway, so I didn't worry about it. YMMV.