If you're a Ruby or Rails developer, you should subscribe to my RSS feed. Rss_icon

Automatically generate Heroku .gems file

written about 9 months ago |
2 comments

One of the greatest parts of Heroku is that it takes care of installing your gems for you. No more /vendor/gems, missing spec files, painful upgrades, etc. In fact, no more /vendor/rails, either. A large number of gems are preinstalled for your dyno, and those are listed at http://installed-gems.heroku.com. If you have any gems not listed there, then you just have to list them in your RAILS_ROOT/.gems file:

ambethia-smtp-tls --version '>= 1.1.2' --source http://gems.github.com
mislav-will_paginate --version '>= 2.3.11' --source http://gems.github.com
thoughtbot-paperclip --version '>= 2.3.1' --source http://gems.github.com
josevalim-inherited_resources --version '>= 0.8.5' --source http://gems.github.com
justinfrench-formtastic --version '>= 0.2.2' --source http://gems.github.com
authlogic --version '>= 2.1.1'

The problem.

This can become a bit of a pain, in terms of keeping your .gems file in sync with the config.gems declarations in your environment.rb file. Luckily, Mark Dodwell posted a little rake task to produce your .gems file automatically.

The improved solution.

I’ve gone ahead and added a small improvement to that task. The version below will ping http://installed-gems.heroku.com and only write out the gems you need that aren’t already installed there. Just put this snippet into lib/tasks/heroku_gems.rake:

namespace :gems do
  desc "Generate .gems file for Heroku"
  task :heroku_spec => :environment do
    require 'open-uri'
    installed_gems = []
    url = "http://installed-gems.heroku.com/"
    open(url).read.scan(/<li>(\w+) [^<]*<\/li>/) do |w| 
      installed_gems << w.first
    end

    gems = Rails.configuration.gems
    
    # output .gems
    dot_gems = File.join(RAILS_ROOT, ".gems")
    File.open(dot_gems, "w") do |f|
      output = []
      gems.each do |gem|
        next if installed_gems.include?(gem.name)
        spec = "#{gem.name} --version '#{gem.version_requirements.to_s}'"
        spec << " --source #{gem.source}" if gem.source
        output << spec
      end
      f.write output.join("\n")
      puts output.join("\n")
    end
  end
end

Comments

9 months ago

Thanks a lot! It wasn’t a big deal to write the .gems file by hand, but this way I realized that most of what’s in /vendor didn’t make sense, especially when you have a kick-ass hosting service like Heroku.

about 1 month ago

Hi Tammer! (Great hanging out with you @ Railsconf this year by the way)

Heroku seems to be smart enough now to ignore already installed gems. Though recently it became dumber in recognizing your Rails version, which you now need to specify in .gems

I was using a standalone rake task to generate the .gems for me. Then I found a nice plugin ‘heroku_san’ by Elijah Miller with several nice heroku rake tasks. Ive updated heroku_san so it can be installed as a gem now too. No more copying .rake tasks between projects!

http://github.com/glennr/heroku_san

Leave a comment:

(click here for formatting tips)