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.

Using Bundler in Real Life

A lot of people have asked me what the recommended workflows for bundler are. Turns out, they’re quite simple.

Let’s step through a few use-cases.

You Get a Repo for the First Time

You’ve just checked out a git (or other) repository for an application that uses bundler. Regardless of any other features of bundler in use, just run:

bundle install

This will resolve all dependencies and install the ones that aren’t already installed in system gems or in your system’s bundler cache.

You Update a Repo Using Bundler

If you update a repository using bundler, and it has updated its dependencies in the Gemfile, regardless of any other features in use, just run:

bundle install

As above, this will resolve all dependencies and install any gems that are not already installed.

You have created a new Rails application

If you’ve created a new Rails application, go inside it and run:

bundle install

This will make sure that Rails’ dependencies (such as SQLite3) are available in system gems or your system’s bundler cache. In most cases, this will not need to install anything.

To check whether your system already satisfied the application’s dependencies, run:

bundle check

As you work in the application, you may wish to add dependencies. To do so, update the Gemfile, and run:

bundle install

You are ready to share your new Rails application

Now that you have a working Rails application, and wish to share, you might wish to ensure that your collaborators get the same versions of the gems as you have. For instance, if webrat specified “nokogiri >= 1.4″ as a dependency, you might want to ensure that an update to nokogiri does not change the actual gems that bundle install will install.

To achieve this, run:

bundle lock

This will create a new file called Gemfile.lock in your root directory that contains the dependencies that you specified, as well as the fully resolved dependency graph. Check that file into source control.

When your collaborators receive the repository and run bundle install, bundler will use the resolved dependencies in Gemfile.lock.

You have a locked application, and wish to add a new dependency

If you add a new dependency to your Gemfile in a locked application, Bundler will give you an error if you try to perform any operations.

You will want to run bundle unlock to remove the lock, then bundle install to ensure that the new dependencies are installed on your system, and finally bundle lock again to relock your application to the new dependencies.

We will add a command in a near-future version to perform all these steps for you (something like bundle install –relock).

You want a self-contained application

In many cases, it is desirable to be able to have a self-contained application that you can share with others which contains all of the required gems.

In addition to a general desire to remove a dependency on Gemcutter, you might have dependencies on gems that are not on a publicly accessible gem repository.

To collect up all gems and place them into your app, run:

bundle pack

When running bundle install in the future, Bundler will use packed gems, if available, in preference to gems available in other sources.

Conclusion

I hope these workflows have clarified the intent of Bundler 0.9 (and 1.0). During our work on earlier versions, the lack of these workflows came up again and again as a source of frustration. This was the primary reason for the big changes in 0.9, so I hope you find them useful.

22 Responses to “Using Bundler in Real Life”

thanks yehuda! looking forward to simplified gem management.

i’m curious: does bundle pack also pack in the compiled native extensions that go along with a gem?

Thanks for clearing things up! I’ve been wondering for ever how bundle pack handles C-extension gems – is the source code kept around? If so, when does compiling happen? If not, what to do with those gems in bundler?

Thanks Yehuda! I found this post to be a great overview of what can Bundler do for me, which is exactly what I was looking for.

i’m seeing this error with bundle pack:
runtime.rb:109:in `basename’: can’t convert nil into String )

all other commands seem to work.

% rails -v
Rails 3.0.0.beta
% ruby -v
ruby 1.9.2dev (2010-02-03 trunk 26544) [x86_64-darwin10.2.0]
% rails myapp
% cd myapp
% bundle pack
Copying .gem files into vendor/cache
  * text-hyphen-1.0.0.gem
  * abstract-1.0.0.gem
  * text-format-1.0.0.gem
  * erubis-2.6.5.gem
  * builder-2.1.2.gem
  * mime-types-1.16.gem
  * sqlite3-ruby-1.2.5.gem
  * memcache-client-1.7.8.gem
  * i18n-0.3.3.gem
/usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/runtime.rb:109:in `basename': can't convert nil into String )
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/runtime.rb:109:in `block in pack'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/runtime.rb:105:in `each'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/runtime.rb:105:in `pack'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/cli.rb:90:in `pack'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor/task.rb:32:in `run'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor/invocation.rb:108:in `block in invo'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor/invocation.rb:115:in `call'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor/invocation.rb:115:in `invoke'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor.rb:137:in `block in start'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor/base.rb:369:in `start'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/lib/bundler/vendor/thor.rb:124:in `start'
        from /usr/local/lib/ruby/gems/1.9.1/gems/bundler-0.9.3/bin/bundle:4:in `'
        from /usr/local/bin/bundle:19:in `load'
        from /usr/local/bin/bundle:19:in `'

I’m glad to see the possible addition of the bundle install –relock option. It’s not to hard to do the other way, but one command is better than three. Is there or will there be a command like bundle pack –prune so the old gems in the cache can be deleted? I know I’ve run into this already.

Also, is there an upgrade path/procedure for people using bundler 0.8.1 and rails 2.3.x to transition to bundler 0.9->1.0?

After I use Bundler for new project and Rails, I can only tell that THIS is really the thing we want for gem dependency!

Really, really nice one!

Next: rewrite rubygems system? :P

Thanks for the use case run down. The UI is a lot clearer than earlier versions.

One use case I’m unsure of is dependencies in a Rubygem. Should they use bundler? How does that fit with a Gemspec?

Any plans to include –list-outdated?

Really really digging Bundler, great work so far. I was wondering why I don’t get a .bundle directory until I lock the bundle. This didn’t make much sense to me since I’m requiring the .bundle/environment file in my application startup.

Could you add some scenario about how Bundler could help with gem development?

E.g. suppose I have a clone of ActiveModel, I18n and maybe additional gems on my disk. Now I’m working on a plugin targeting ActiveModel but also relying on I18n. I want each of the gems to use my local repository clones so I can easily go in there for debugging or maybe even tweaking things. But in order to keep this maintainable and share-able I obviously don’t want to mess with my gems setup manually (e.g. symlinking directories) or even hardcode filesystem paths. Oh, and ideally I’d want to be able to run particular parts of the AMo test suite from within my plugin’s test suite so I can ensure I don’t break the API.

Is this something Bundler can help me with? I suppose it’s a scenario that you guys eat deal with every day :)

Thanks :)

@trever, I had the same error message.

I had originally specified a bundle_path of vendor/bundler_gems in my Gemfile. I remmed it out, and rm -rf vendor/bundler_gems.

Then did “bundle install vendor/bundler_gems”.

“bundle pack” then worked without error. They key to get rid of the error was to rm -rf the old structure.

I think it has something to do with the relative path.

BJ Neilsen: you need to change your preinitializer to: http://gist.github.com/298545#file_preinitializer.rb

Won’t bundle unlock; bundle lock update ALL gems in my project to the latest gems on my system? Seems a bit scarier of an operation than you imply.

Bundler rocks BTW. Handling gems in complex Rails apps used to be a real problem.

@SvenFuchs This I would like to know also.

No amount of hackery or tom foolery has made it work for me in rails 2.3.x on a fresh app or otherwise… So seems there is still much work to be done before 1.0. I was and will continue to use 0.8.1 until then.

@sven, @christian – rvm may be able to help you with this scenario to some extent. If not out of the box and you can make a decent case for it Wayne would probably help you get it added. He’s been tremendously helpful.

http://rvm.beginrescueend.com/

Is there any talk of integrating Bundler into rubygems? Using a Gemfile instead of .gemspec for dependencies would provide consistency when creating either an app or a gem. IMHO, Bundler is gem++.

gem check –gemfile
gem install –gemfile

Hey folks, Brad from Poll Everywhere here. We’re upgrading to bundler 0.9.5 and ran into a questions using Bundler with git.

First, should the .bundle folder be ignored? If so, there is an issue when another developer pulls a project and runs ‘bundle install’. The bundler gets to the end of the install process and blows up because .bundle/environment.rb is not found. The error messaging isn’t very clear around this problem either, but a ‘bundle lock’ command fixes it since the generates the .bundle folder. I’m positive that .bundle should be ignored in .git because it contains absolute paths to the gem files, so the bundle install command should probably generate this file if its not present.

Is there a recommended way to deploy apps that use bundler? Hopefully bundler 1.0 will come with some capistrano recipes or something.

Similar to @BradGessler’s question: How do you handle multiple developers working on a project? It seems common that developers could use different gems in their dev environments. Database systems are the first that come to mind. Some developer might use sqlite while another uses mysql.

when i “bundle install –disable-shared-gems” All the gems are installed from system gems, shouldn’t this force the gem repo into my application… the concern is having to rely on the environment for things like

which unicorn_rails

where as before it could be known that unicorn_rails would always be in the APP_ROOT/bin

Make sense?

Hi, thank you for this post about workflows with bundler!
However, I’m missing how to deal with locking when deploying in situations where some gems are in the development group, but not in the production group and vice-versa.
After deploying the app with capistrano, I find myself connecting to my production box, removing the gemfile.lock and running bundle install –without development.
Given how sharp and clear the organization of your projects is, I’m certain that I’m missing some fundamental concepts…

Leave a Reply

Archives

Categories

Meta