Jay Fields blogged recently (and not for the first time) about managing gems within Rails projects. This is a problem a lot of people have wrestled with; there are close to a dozen plugins, rake tasks, uncommitted patches, and published hacks that attempt to provide a solution (and those are just the ones I know of).
FrozenGemsGenerator is the solution that we’ve been using on some projects at Relevance, and we’re happy enough with it that we’ll be using it more. It’s a rails generator, packaged as a gem, that gives your Rails app a private gem repository, fully self-contained, and manageable just like your system-wide repository (except using script/gem instead of gem).
$ sudo gem install frozen_gems_generator $ script/generate frozen_gems $ script/gem install money
script/gem supports all of the subcommands that the regular gem command does.
I haven’t yet implemented a solution for gems that install binary extensions. I’m very interested in suggestions for how best to solve that problem. Several of the other approaches have at least partial support for architecture-specific gems; the best may be Jeremy Voorhis’ CarryOn plugin, which is also the solution that’s closest in spirit to the FrozenGems approach. If you have ideas or suggestions about how architecture-specific gems should be handled, please add comments here or post them on our Trac instance.
I’d be curious if you’ve looked at geminstaller (http://geminstaller.rubyforge.org/). This is what we’re using at Bring Light and I’m using it on some other projects. GemInstaller, as a simple explanation allows you to define a YAML file that indicates what version(s) of gems your app requires. It then ensures those gems are installed (and has an option to install them if they aren’t), and puts those specific versions on the load path. It has some nice advantages in my mind: - No need to pollute your source control with gems. This speeds up your source control, your deploy time, etc. - Solves the architecture/platform specific problems (because it uses what is installed on your system as per your version requirement). - Is easy to add to a Rails app – especially a Rails 2 app where you can just plop another file into the config/initializers directory. - Can install missing required gems at app startup time, at deploy time, or really at any time (just run geminstaller anytime you like). This is also nice to bootstrap someone’s development environment. - Plays nice on your system with having multiple versions of gems. This is awesome for any of us who work on multiple Ruby/Rails projects where those projects might be using different versions (obviously this is a major part of this whole problem in general and the reason behind freezing, etc.). - Seems even more obvious in terms of knowing what versions of gems you are using – the geminstaller.yml file is a simple thing to look at and see what versions you require, whereas frozen gems often don’t indicate what version they are.
Chad Woolley at Pivotal Labs implemented this, and I believe that most Pivotal projects use it as well.
Chris: yes, I’ve looked at geminstaller, plus several other systems that involve keeping lists of gems you need. And you’re right about those advantages. But I really do want to have the gems themselves in our source control system (for the same reason that we use piston for our plugins) and I want to have all the same tools available for managing gems in rails apps that I use for managing gems in my system … the ability to check for updates, automatically upgrade, install and remove gems easily, and so forth. That’s what FrozenGems gives us.