Bundler makes life much easier for us Rails devs, but there is currently one thing on the wishlist that I would like to see implemented. Bundler already lets you specify a local path for a gem and also lets you choose github as the source of the gem. My problem is that Bundler does not allow you to add the same gem in development and production with different sources. Why do I need multiple sources? I work with quite a few custom gem engines in my rails apps and sometimes I run into issues that I need to debug or I find new features that I want to add to one of my gems. It would be a real pain to git commit, push, bundle update and then restart my server every time I need to change something in one of my custom engines and view it in my rails app.
Here is what I was trying to do initially before I understood how Bundler worked with environment groups:
group :production do gem 'mygem', :git => 'git@github.com:me/mygem.git' end group :development do gem "mygem", :require => "mygem", :path => "/gem_dev/mygem" end
Bundler no likey: You cannot specify the same gem twice coming from different sources.
I suspected I was not the only one that wanted something like this, so after looking at the github issue list I found a simple solution in the comments for this wishlist issue . Use an environment variable and put a condition in your Gemfile like so:
if ENV['MY_BUNDLE_ENV'] == "dev" gem "mygem", :require => "mygem", :path => "/gem_dev/mygem" else gem 'mygem', :git => 'git@github.com:me/mygem.git' end
Don’t forget to set your environment variable in you command shell:
export MY_BUNDLE_ENV='dev' bundle install
Now I can work with the gem from my local path. But, lets say I want to deploy to production. There are 2 ways you can approach the production deployment:
Option 1: For those that live on the edge, you will keep your Gemfile pointing to your master github repo
Option 2: For those who are scared to live on the edge, you should probably tag your code in github for your latest stable version and add your tag , :tag=>'v1.0.0' to the end of the production gem line.
Either way, you will need to install your bundle locally and then commit your Gemfile.lock (and Gemfile if changed) to github. I tried a rake task to do this at first, but since rake loads your app, it will crap out and ask you to bundle install before the task can actually change the ENV var (I think that was the problem??). I wasted quite a bit of time trying to figure out a workaround using rake with no luck, so against my will I created a simple shell script to speed up the process.
APP_PATH="/path/to/your/rails_app" cd $APP_PATH export MY_BUNDLE_ENV='prod' bundle install git commit -m 'new Gemfile' $APP_PATH/Gemfile git commit -m 'new Gemfile.lock' $APP_PATH/Gemfile.lock git push export MY_BUNDLE_ENV='dev'; bundle update
This script sets your environment variable to “prod”, runs a bundle install and then commits and pushes your Gemfiles to github. Then it sets the environment var back to dev and runs a bundle update (don’t need install since you are using local paths) so you can keep working locally after the push. Now your app has the proper gems in Gemfile.lock in your github repo and the last step is to deploy it to prod… I use Capistrano and my app server is Passenger. Here is my recipe for the bundler step (ripped off from somewhere else of course
)
namespace :bundler do
task :create_symlink, :roles => :app do
shared_dir = File.join(shared_path, 'bundled_gems')
release_dir = File.join(current_release, 'vendor', 'bundle')
run("mkdir -p #{shared_dir} && ln -s #{shared_dir} #{release_dir}")
end
task :bundle_new_release, :roles => :app do
bundler.create_symlink
run "cd #{release_path} && bundle install --deployment"
end
end
after "deploy:update_code" do
bundler.bundle_new_release
end
UPDATE: Looks like a deployment cap recipe is included in Bundler now, so you should probably use that instead. MAN, THESE GUYS MOVE FAST!!!
This recipe will run Bundler deployment after the code has been updated (so it can see the new Gemfile). Works well for me so far. It would be easier if Bundler supported the first syntax I tried, but this ain’t to difficult to add.
As always, comments and corrections are welcome.
UPDATE 2: This issue will be fixed in version 1.1 according to @wycats
mrreynolds: @wycats Any chance Bundler could support multiple sources for one gem per env? Otherwise we need such hacks:http://bit.ly/bjdk0C
wycats: @mrreynolds the :git/:path issue is scheduled for 1.1



