Managing a distributed Rails application without Capistrano is painful at best. If you have ever had to do it you know what I am talking about.
Capistrano makes things much easier. Case in point is updating your gems across multiple servers. Here is the Capistrano recipe that we use to keep gems updated:
desc "Update ruby gems"
task :update_gems, :roles => [:web, :admin, :app] do
cmd = "/usr/local/bin/gem update --include-dependencies"
sudo cmd do |channel, stream, data|
puts "#{channel[:host]}: #{data}"
if data =~ /([12])\.[^\(]+\(ruby\)/
channel.send_data "#{$1}\n"
end
end
endNow, you’ll probably need to customize it to your own needs. For instance, change the roles to suit your own setup. Also, you may want to modify the path to your ‘gem’ executable, and configure ’sudo’ to allow your user to run that command without a password. You’ll have to do that on each server as follows:
sudo visudoThen add a line like this:
myuser ALL=(ALL) NOPASSWD: /usr/local/bin/gem update --include-dependencies
If you don’t have access to ‘visudo’ ask your administrator.
Also, Win32 users will need to change the regular expression from this:
if data =~ /([12])\.[^\(]+\(ruby\)/to this:
if data =~ /([12])\.[^\(]+\(mswin32\)/… so Capistrano will choose the correct version of the gem to use.
Basically this recipe will run the ’gem update --include-dependencies’ command and analyze the output choosing the correct latest version of gem to install.
Many, if not most, Rails applications require an administration interface, which allows a certain group of users to perform maintenance and administration tasks on the application and its underlying data.
Sometimes it is beneficial to move the administration interface to its own server. However, most applications do not use a separate project for the administration interface. It can be done that way but then you need to share models between two projects.
I accomplished this by having the project code on multiple servers, and configuring one of those servers to host the admin interface, which is simply a set of controllers within the main application:
app/controllers/admin
So, I setup a before_filter that simply forces a redirect based on the request URI. In other words if the URI begins with /admin we force a redirect to the server hosting the admin interface like this:
def check_and_redirect_admin_domain
if ['production'].include?(ENV['RAILS_ENV'])
using_dot_biz = (request.host =~ /\.biz$/)
if !using_dot_biz && request.request_uri =~ /^\/admin/
full_url = request.protocol + request.host
full_url += ':' + request.port.to_s if request.port
full_url += request.request_uri
full_url.gsub!(/\.com/, '.biz')
redirect_to full_url and return false
end
end
endOur administration interface is hosted on a .biz domain, while our application is hosted on the .com domain. First we check to see if the environment is running on production. If it is, check if we are already on the .biz domain, or if it is being requested directly by the user. If it is not, and the requested URI begins with /admin, we build and execute our redirect.
This effectively partitions our application so the admin interface runs on a different server. We also setup separate mongrel instances and a separate database connection which uses one of the DB mirrors.
