Environment & Source Control
The Ruby ecosystem has tens of thousands of Gem libraries we can utilize in our programs. A typical Rails application might rely on 50 libraries. In the days of Rails 2 managing these dependencies was a real challenge, especially when coordinating multiple machines and developers.
As the core team built Rails 3, they addressed this problem by creating Bundler (http://gembundler.com/). In our project we create a
Gemfile which specifies our gem dependencies and source(s). Using that file, Bundler can resolve the complex interactions of library dependencies and install/utilize gems as needed.
A very simple
Gemfile might look like this:
1 2 3
From the terminal, in the project directory, we can process this
Gemfile and setup the dependencies with one command:
install is the default
bundle command you can omit it, like so:
Bundler will attempt to utilize gems already installed on the system to meet the dependencies, fetching additional gems from the "source" (in our example RubyGems) as needed.
Once in awhile you’ll want to run
bundle when you’re offline. To tell Bundler to only use locally installed gems, add the
local flag like this:
Most Ruby libraries move fast, some move incredibly slowly. While there are established Version Policies (http://docs.rubygems.org/read/chapter/7) for RubyGems, their implementation is spotty at best. Using the above
Gemfile, our application would (at the time of this writing) pull down Rails version 3.0.10 and Rake 0.9.2.
Six months from now, though, it might pull down Rails version 3.2.0. Will that break our application? Probably. So we should lock our gems down to specific versions. Adding exact versions to the above
Gemfile would look like this:
1 2 3
But what about bug and security fixes? I can build against Rails 3.0.10, but if a security issue is found they’ll release a 3.0.11. The third number is called the "patch level", and when it increments it should be completely backwards compatible. 3.0.11 should introduce no issues for an app built against 3.0.10. This rule generally holds true.
But patch levels are released every few weeks. This can make keeping the
Gemfile up to date a real pain. We can add some flexibility to our dependencies with the "squiggle-rocket" operator:
1 2 3
Now Bundler will use Rails version
3.0.11, or any patch level in the
3.0.* series. It will not, however, use
This is usually the ideal behavior. Upgrading the "minor" version, from
3.1, is likely to necessitate changes in your application.
Managing Edge Code
Often you’ll be developing a gem while you’re developing an application that uses it. Or, sometimes you’ll need to use the absolute bleeding edge code for a Gem before it’s released on RubyGems. In that case, Bundler can resolve dependencies directly from Git or GitHub:
1 2 3
Building an application using git-based dependencies is an extremely bad idea unless you control the repository. The easiest way to do that is fork the repository on GitHub, then reference your fork in your
Gemfile. You can keep your fork up to date by adding the original repository as an upstream remote (https://github.com/MarkUsProject/Markus/wiki/Gitkeepingpace).
Unless you have a lot of time to waste and enjoy frustration, never build against "Edge Rails" as shown here.
Many gems provide command-line executables, like
Old vs. New
When you run
rake at the command line, for instance, your system searches its
PATH for a matching executable. If you had both Rake versions
0.9.2 installed, which one would it use? Rubygems will cause the system to use the newest installed version.
But your application might be written with
0.8.7. There isn’t a way, using the normal command line, to force Rubygems to use the older version.
Running in Your Bundle
Bundler provides a command line function
bundle exec. When you run
bundle exec, Bundler will:
- sandbox execution so your system gems are not accessible
- load the gems specified in your
- then run whatever command you add after the
So, for example:
Would force usage of the version of Rake specified in your project’s
Gemfile, regardless of what other versions are installed in the system gems.
Once your project has a
Gemfile, it is a good practice to prefix every command line instruction with
bundle exec. So you might do operations like:
bundle exec rake db:migrate
bundle exec rails generate model Article
bundle exec rspec spec
It’s a pain to type
bundle exec all the time, so some developers will create an alias in the OS to
be rake db:migrate, etc.
On MacOS or Linux you could create such an alias by opening your
.bash_profile and adding this line:
alias be="bundle exec $1"