Development with Mercurial
Distributed Source Code Management is the wave of the future, and I can't say enough good about it. My prefered system is Mercurial (aka hg), which I got to know why working on the Xen project. While git is getting a lot more hype of late, I still think hg is easier to use, and an easier switch for people that know subversion.
Rails makes it very easy to run a server locally for development, so having versioning locally makes perfect sense. I can hack away for days making changes on my laptop until I get to a point where I want the code to see the light of day. Then it is an easy hg push to put my code either into production, or into a repository for sharing.
Deployment with Passenger
Passenger is a god send. Getting mongrel to do the right things on init on an ubuntu box was just a pain in the rear end. I like apache, I know apache, having to configure a web app outside of apache sucks. Passenger builds an apache plugin that is an rails app server. You don't need to know any more than that, because it just works.
Actually, you need to know 2 things, both of which add to passenger's awesomeness.
- The rails app will run as the uid of the owner of your environment.rb file. This means you need to take care on how your permissions work on you deployed rails app. This is a good thing, as we'll see in a minute.
- You don't need to restart apache to restart the rails app. You just need to touch tmp/restart.txt in the rails directory, and the app server restarts. This is very handy.
Bringing it all together with Mercurial Hooks
On my box where I'm deploying applications I created a new rails user, with a scrambled password, and just my ssh key to get in. This is the account in which I push production versions of apps to. It means that the rails apps run as user rails, which is ever further issolated than user www-data. You could even go a step further and have each rails app under a different user, but for me that's overkill.
The .hg/hgrc for one of my local projects looks as follows (with myhostname, myrailsapp, and myrailssite replaced to protect the innocent):
default = ssh://myhostname.org/code/myrailsapp/
production = ssh://firstname.lastname@example.org//data/site/myrailssite/
Now my push targets are in place.<br /><br />The last bit is adding a set of hooks on the target repository so that on each push the repo is updated, migrations are run, and the app is restarted. I've created /data/site/myrailssite/.hg/hgrc as follows:
incoming = hg update -C && RAILS_ENV=production rake db:migrate && touch tmp/restart.txt
And that's it. Now an hg push production force syncs the remote repo, runs any new migrations, and restarts passenger. A 1 step command, and everything is live.
While I've been a huge Ruby on Rails fan for the last year, deployment always sort of sucked with it. Now I'm a very happy camper with this setup which makes for very seemless development of rails applications.