A couple of weeks ago, I read an interesting tweet from Chris Wanstrath – it read a little something like this “Every time you use sudo to install a gem, an angel loses its wings”.
It got me to thinking, what exactly could he mean, we’ve all used sudo to install gems at some stage, and many of us don’t see a problem with it, at least I never had.
So, I came up with a few thins that were bugging me about it, and want to try and debunk a few of the myths about gems..
What about sharing gems with system processes, most notably Passenger mod_rails?
This one bugged me, if I install a gem – and I am developing – I do not want to have to install this gem twice, once for me, once for the system, and moreover – if I do install this gem twice – should I install the other one as the apache or www (delete as appropriate) user, or using sudo.
You have no excuse! When installing a gem, if it has a executable component (think haml . --rails and capify ., rake, etc) the installer process will warn you with a concise and clear explanation, the gist of which is that if you locally install a gem without ~/.gem/ruby/1.8/bin/ in your PATH then running these executables won’t work.
I don’t think this is an unfair sacrifice to make, and we’ve all altered our PATH for less; my only suggestion on this point is to make this change not in your local dot files, but in /etc/profile.
So, locally installed gems; works pretty nicely how should we make them available to our production application?
Firstly, make sure you are using some kind of declarative gem dependency specification personal taste aside I think any one of Bundler, Rip, Gem Installer or Rails’ own config.gem does a pretty good job – the key thing is that at deploy time, or before – you have a mechanism for determining what must be installed for your application server to run.
This can take a couple of forms – either you take the advice of Jay Fields and Ryan Bates, and unpack the gems – this leads to two further roads, do you bundle these into your SCM system, and deploy them each time, or defer this action to the server at deploy time, or take another option?
The plot thickens when you take into account login shells, versus non-login shells; Apache will ignore the /etc/profile file; as mentioned above unless you add the suggested line to /etc/apache2/envvars – the Apache documentation on this topic says “If you wish to manipulate the operating system environment under which the server itself runs, you must use the standard environment manipulation mechanisms provided by your operating system shell.” – their documentation makes no mention of the envvars file – so there’s a good chance this is operating system dependant, the safest thing to do all round is package your gems with your application unless you have a smart system administrator to take care of the Apache configuration for you.
Advice: Let your system guys decide; and if you are the system guys, do what suits you best; I dare argue that in this case it is acceptable to sudo install the gem, for use by the system. If you must mess with your web servers configuration, do it in the start-up scripts; this way you can at least be declarative about these too.
/etc/profile Apache and /etc/apache2/envvars – and Macs
If you’re wondering why I’m suggesting using /etc/profile rather than your local dot files comes back to the question regarding installing your Passenger mod_rails gems using sudo or not; if your apache instance honours the /etc/apache2/envars file, you can add here a line like source /etc/profile and share system-wide configuration.
Note: Since I am neither responsible for any worthwhile deploys anymore, and I only develop on a Mac – my advice in this area might be a little short sighted!
How do I do it?
Well, I install local gems, and rely on config.gem at deploy time; this works perfectly for me, and also works quite nicely for sharing gems between different versions of Ruby using [Ruby Version Manager (a.k.a rvm)])(http://rvm.beginrescueend.com/) – which recently threw another spanner in the works in the form of Named Gem Sets which thankfully stays out of the way!
Feedback
Please discuss, I have a lonely comments system, or mention me on twitter @leehambley – I’d love some feedback from people on this, I’m sure there are smarter ideas than mine!