November 24, 2008

Posted by John

Tagged gems and rubygems

Older: Git'n Your Shared Host On

Newer: Unless, The Abused Ruby Conditional

RubyGems: Yours, Mine and Ours

I get a lot of ideas, so many in fact that I would never want to purchase a Slicehost, Railsmachine or Engine Yard slice for each one. I would run out of money in a few weeks. Instead, I put most of my ideas through a trial run on a shared host (DreamHost). If I find myself using the application a lot and needing performance to improve, I’ll bump it up to a slice on one of the aforementioned hosts, but until then the app will sit in shared-ville.

As such, I have spent a lot of time battling Rails on DreamHost. Back in the old days (fcgi), I had cron jobs running Ruby scripts and all kinds of tweaks trying to keep my DreamHost rails apps going. I finally gave up on DH and bought a slice at slicehost (whose site we at Ordered List designed).

I’m happy to say that the battle is now over. It is really easy to host your own git repositories, install your own version of Rubygems and deploy your Rails apps on DreamHost with passenger (mod_rails). Don’t expect DH to amaze you with performance, but for tiny apps with a few users (or heck just for yourself), Dreamhost is a cheap and really viable option.

Your Own Version of RubyGems

Rest assured I’ll cover setting up and deploying an app in a future article, but for now I am going to show a quick and easy way to install your own gems on Dreamhost (or virtually any shared host you have ssh access to) and how to tweak Rails to obey (if necessary). Installing RubyGems in your home directory, as I am about to show you, allows for installing gems without sudo, which most shared hosts deny.

To get going, ssh into the server you would like to install RubyGems on and then run the commands below. For now copy and paste, but I have a gem in the works that will automate this someday. If you are going to follow along, I would practice on something that doesn’t matter first to see if you run into anything.

# group 1
cd ~
mkdir .gems bin lib src

# group 2
echo 'export GEM_HOME="$HOME/.gems"' >> .bash_profile
echo 'export GEM_PATH="$GEM_HOME:/usr/lib/ruby/gems/1.8"' >> .bash_profile 
echo 'export PATH="$HOME/bin:$HOME/.gems/bin:$PATH"' >> .bash_profile
source ~/.bash_profile

# group 3
cd ~/src
wget http://rubyforge.org/frs/download.php/43985/rubygems-1.3.0.tgz
tar xzvf rubygems-1.3.0.tgz
cd rubygems-1.3.0
ruby setup.rb --prefix=$HOME
cd ~/bin
ln -s gem1.8 gem
cd ~

# group 4
which gem   # should return /home/USERNAME/bin/gem
gem -v      # should return 1.3.0

# group 5
gem update --system

The first group of lines creates the needed directories. The second group of lines ads 3 lines to your .bash_profile file. Basically, it sets your GEM_HOME to ~/.gems and your GEM_PATH to look first in your GEM_HOME and then look at DreamHost’s typical gem path. The final line of that group sets the PATH to check ~/.gems/bin first and then look in the normal path for binaries.

The third group downloads version 1.3.0 of RubyGems into your ~/src directory, untars it, and runs the setup file to install RubyGems. It then cds into your ~/bin directory and creates a symlink from gem to gem1.8 so you don’t have to type gem1.8 install somegem.

Group 4 verifies that everything went ok and is just a sanity check and the last line, group 5, updates RubyGems to the latest version. I don’t really want to update this article for every RubyGems update so be sure you run this command to get the latest version.

Now that you have RubyGems installed, you can install any gem by issuing the normal gem install command. The nice thing is that sudo is not needed as the gems are installed in your home directory, which you have permissions for.

Tweaking Rails

For whatever reason, DreamHost was ignoring the GEM_PATH and first looking in their gems, only looking in my gems if they did not have it installed. The easy fix for this is to put the following line at the top of config/environment.rb (if someone knows a better way, let me know).

ENV['GEM_PATH'] = File.expand_path('~/.gems') + ':/usr/lib/ruby/gems/1.8'

The line above tells Rails to look first in your custom gems and then at DreamHost’s installed gems. You only need to do this if DreamHost has an older version of a gem you are installing and you specifically need the newer version. I ran into this with RedCloth 4, which is not installed on my DreamHost server, as of the writing of this post.

Conclusion

If you followed the few lines above, you can now install your own version of RubyGems on a shared host, install your own gems (with gem install foo) and use those gems in your Rails apps. One thing I did not mention is you can use the vendor everything method for any gems that don’t need to build extensions. Thought I would put that out there too.

Hope this is helpful. If you decide to give DreamHost a shot (who I recommend among shared hosts), use RAILSTIPS as the promo code. It will give you $30/off and I get a kickback as well.

5 Comments

  1. Per Velschow Per Velschow

    Nov 25, 2008

    Are you sure that your rails app is in fact using your installed version of RubyGems? I believe that Passenger is booted from an environment in which your local setup is not in effect. This could account for the problem with GEM_PATH not being set as you expect.

    By changing GEM_PATH later in the boot process, you can indeed get DH’s ruby to load your own gems. But this happens after rubygems itself has been loaded. I noticed this problem a while back when a new version of Rails (2.1.1 I think) suddenly required rubygems 1.2. At the time my DH server had a very old version of rubygems which made it impossible to use that version of Rails. That’s when I gave up on using Rails on DH!

    On my DH account the official RubyGems is actually now version 1.3.0. Maybe it’s the same on yours and that’s why it appears to work fine right now. But have you tried running the latest Rails version 2.2.2? I believe this requires RubyGems 1.3.1. My guess is that this will fail unless the DH version of RubyGems is also 1.3.1.

  2. @Per – The app most likely is not using the installed version of RubyGems. The main goal is just to be able to install gems myself. I guess for that you could just do the path stuff and forget the actual install of RubyGems. I haven’t tried to run with the latest version of Rails yet but I’ll give that a shot at some point.

  3. This also would be useful if you use Continuous Integration (e.g. cruisecontrol.rb) and want to isolate each project to using specific gems only.

  4. Jacob Radford Jacob Radford

    Dec 01, 2008

    John, I’ve written a gem called sandbox that attempts to create isolated gem environments for projects. While it is basic, I’m hoping to flesh it out and allow for installing different version of ruby/rubygems. I’ve only tested with bash as my shell – that’s what the activate script it installs expects.

    I’d be curious if this could be of use on DH (if they had it installed as by default). My thinking is that if it was installed system-wide, you wouldn’t need many system-wide gems.

    I’ve spent the last year+ working with Python at work and sandbox is a direct result of working with Python’s virtualenv which is awesome. Ruby is preference, so I wanted to port that tool over. Then I read this article and thought it might be made to work for what you need.

  5. @Jacob – That looks pretty cool. I’ll check it out when I get a chance.

Sorry, comments are closed for this article to ease the burden of pruning spam.

About

Authored by John Nunemaker (Noo-neh-maker), a programmer who has fallen deeply in love with Ruby. Learn More.

Projects

Flipper
Release your software more often with fewer problems.
Flip your features.