Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; his 9-to-5 home is at the startup he founded, Tilde Inc.. There he works on Skylight, the smart profiler for Rails, and does Ember.js consulting. He is best known for his open source work, which also includes Thor and Handlebars. He travels the world doing open source evangelism and web standards work.

What’s New in Bundler 1.0.0.rc.1

Taking into consideration the huge amount of feedback we received during the Bundler 0.9 series, we streamlined Bundler 1.0 significantly, and made it fit user expectations better.

Whether you have used bundler before or not, the easiest way to get up to speed is to read the following notes and go to http://gembundler.com/v1.0 for more in-depth information.

(note that gembundler.com is still being updated for the 1.0 changes, and should be ready for the final release).

Starting a new project with bundler

When you generate a new Rails application, Rails will create a Gemfile for you, which has everything needed to boot your application.

Otherwise, you can use bundle init to create a stub Gemfile, ready to go.

First, run bundle install to make sure that you have all the needed dependencies. If you already do, this process will happen instantaneously.

Bundler will automatically create a file called Gemfile.lock. This file is a snapshot of your application’s dependencies at that time.

You SHOULD check both files into version control. This will ensure that all team members (as well as your production server) are working with identical dependencies.

Checking out an existing project using bundler

After checking out an existing project using bundler, check to make sure that the Gemfile.lock snapshot is checked in. If it is not, you may end up using different dependencies than the person who last used and tested the project.

Next, run bundle install. This command will check whether you already have all the required dependencies in your system. If you do not, it will fetch the dependencies and install them.

Updating dependencies

If you modify the dependencies in your Gemfile, first try to run bundle install, as usual. Bundler will attempt to update only the gems you have modified, leaving the rest of the snapshot intact.

This may not be possible, if the changes conflict with other gems in the snapshot (or their dependencies). If this happens, Bundler will instruct you to run bundle update. This will re-resolve all dependencies from scratch.

The bundle update command will update the versions of all gems in your Gemfile, while bundle install will only update the gems that have changed since the last bundle install.

After modifying dependencies, make sure to check in your Gemfile and Gemfile.lock into version control.

By default, gems are installed to your system

If you follow the instructions above, Bundler will install the gems into the same place as gem install.

If necessary, Bundler will prompt you for your sudo password.

You can see the location of a particular gem with bundle show [GEM_NAME]. You can open it in your default editor with bundle open [GEM_NAME].

Bundler will still isolate your application from other gems. Installing your gems into a shared location allows multiple projects to avoid downloading the same gem over and over.

You might want to install your bundled gems to a different location, such as a directory in the application itself. This will ensure that each application has its own copies of the gems, and provides an extra level of isolation.

To do this, run the install command with bundle install /path/to/location. You can use a relative path as well: bundle install vendor.

In RC1, this command will use gems from the system, if they are already there (it only affects new gems). To ensure that all of your gems are located in the path you specified, run bundle install path --disable-shared-gems.

In Bundler 1.0 final, bundle install path will default to --disable-shared-gems.

Deployment

When deploying, we strongly recommend that you isolate your gems into a local path (using bundle install path --disable-shared-gems). The final version of bundler will come with a --production flag, encapsulating all of the best deployment practices.

For now, please follow the following recommendations (described using Capistrano concepts):

  • Make sure to always check in a Gemfile.lock that is up to date. This means that after modifying your Gemfile, you should ALWAYS run bundle install.
  • Symlink the vendor/bundle directory into the application’s shared location (symlink release_path/current/vendor/bundle to release_path/shared/bundled_gems)
  • Install your bundle by running bundle install vendor/bundle --disable-shared-gems

15 Responses to “What’s New in Bundler 1.0.0.rc.1”

Please be sure to update the docs to include examples of how to get gems like ‘mysql’ and ‘rsruby’ to build on remote servers. This has always been a sticking point and with the eventual forcing of ‘–disable-shared-gems’ by default, will become a much bigger deal.

Thanks.

First of all: congratulations on the RC1 release! It’s a difficult project and you’ve nailed it! Bundler rocks!

Second: I was wondering what the real purpose of the “bundle”-command is, without any arguments. It looks like it does the same, but you don’t mention it in this post and the website doesn’t mention it either. What should I use?

Thanks a bunch, Yehuda. This is great news, and hopefully there will be a general release soon. Please let us know if you need anything to speed this up. The community is at your disposal.

So if I check in my local Gemfile.lock, and it has references to things like autotest-fsevent and autotest-growl, won’t that blow up on Linux?

This is great, much better workflow than 0.9x series, especially for deployment. Running `bundle check && bundle install vendor/bundle –disable-shared-gems` with capistrano will update only what’s necessary.

Thanks Yehuda!

I thought it was worth pointing out that when running ‘bundle install’ for the first time on the RC (was using the latest beta prior to that), it will actually do a “bundle update”. This has happened for me at least, using a Rails 3 project with Haml 3.0.13, which has been updated to 3.0.14. This does not seem to be reproducible afterwards, bundle update and bundle install worked just as smoothly as you described it here.

@bryanl: Seems to me some kind of platform-based dependency block in addition to groups might make sense?

I’ve been using Rails 3 for a little over a month now, and I can happily say that Bundler 0.9 has been a massive time-saver and a huge productivity win. Bravo! This is NOT a trivial problem and Bundler is amazingly elegant.

The issue I want to bring up is the behavior of ‘bundle install [path]‘. The behavior of ‘remembering’ this path, while sensible, can really lead to some surprises.

We had a new Ruby developer (indeed, we are ALL new Bundler users) inadvertently use this command when trying to install a gem directly, thinking he needed ‘bundle install [gem_name]‘. Of course, this appears to work and one goes about their business, only later finding a [gem_name] directory in the project root full of gem directories. This is downright spooky!

The problem is exacerbated when using rvm (rapidly becoming a Ruby best-practice) and by a lack of documentation. Writing the BUNDLE_PATH variable to [project_root]/.bundle/config (which shadows the environment var that rvm correctly but ineffectually sets) doesn’t seem to be mentioned anywhere, indeed, I can’t find ANY mention of this config file and its options anywhere on gembundler.com!

Solutions:
- I’d like to see the ‘bundle install [path]‘ broken out into a separate command. I feel like it violates ‘least surprise’ to have the normal, run-of-the-mill ‘install’ command change global state. I’m flexible on this part, though, since it is certainly learnable.

- Documentation in 2 places (this is a must):
1) on the page describing ‘bundle install’ (http://gembundler.com/v1.0/bundle_install.html), where it says “Further bundle commands or calls to Bundler.setup or Bundler.require will remember this location” should clearly reference the mechanism it uses to remember the location: the config file and accompanying option.

2) a dedicated page for the config file. Where does it live? What options are there? When should I make changes to it and why?

- Finally, I’d love to see a writeup on using Bundler with rvm. The two clearly have some overlap and I’d like to know the best practices when using them together. rvm silos gems for different Ruby versions, but it also provides gemsets which allow you to further silo your gems. Which responsibilities fall into the realm of rvm, and which are better left to Bundler’s formidable functionality?

Thanks again, Yehuda. I’ll be happy to contribute some of this, but I wanted to give you the chance to tell me I was wrong, first!

I’ve made a gist with capistrano config code that follows the deployment advice in the post; feel free to use and improve:

http://gist.github.com/493313

Great news that things are slowing down around here! I wanted to ask what is your proposed solution to comitting the Gemfile.lock – which often contains group(:test) dependencies (at least on developer workstations) when moving to production, I have seen this cause problems.

I needed to uninstall bundler-1.0.0.beta.5 before rc.2 would cooperate. It was loading Thor out of the beta.5 gem, and that made the resolver unhappy. With beta.5 gone, all is right with the world again.

http://gist.github.com/502312

I am deploying via Capistrano with a user who cannot sudo. I really have big problem deploying and installing the gem with native extensions.

The gem installing script tries to do something like
make install
/usr/bin/install -c -o root -g wheel
..and it crashes.

In the past I was managing the native extension gem separately via puppet. But now I don’t know what to do.

Should I start deploying with a user who can sudo? It sounds bad!

Wow. I’ve read numerous “Getting Started” posts for bundler, and this is the first time I’ve finished and thought to myself, “Wow that seems incredible easy and useful.”

Thanks.

So… if you’ve recently run a sudo (or if you have NOPASSWD in sudoers) then bundler will casually grab root to install downloaded gems.

Not clever.

bundler should not take sudo without explicitly asking or without a –sudo option.

I’ve been struggling with all the dependencies I have in development that I don’t really want on my production server (spork, cucumber, etc.). I was thinking I could create a Gemfile.development and Gemfile.production that would really server as templates for developers, then have a Gemfile.lock.development and Gemfile.lock.production. When a developer is adding a gem for production use, they would just copy the Gemfile.lock to Gemfile.production. On deployment, we would copy the Gemfile.production to Gemfile and likewise with the .lock file. I realize it’s a bit of a pain, but I can’t come up with a better way to avoid installing lots of things that aren’t needed. Comments or suggestions?

@Spencer, Bundler already has this built in.

You can put your gems into groups, such as :development, :test, :cucumber. When you run bundle install on your production server, you just run “bundle install –without cucumber development test”, and it won’t install any gems you have put in those groups.

Leave a Reply

Archives

Categories

Meta