The Problem

Using subdomains with Rails is kind of a pain. The only official support for subdomains is as asset hosts, as described in the AssetTagHelper documentation.

Matthew Hollingworth’s subdomain_routes covers most of the gaps in dealing with subdomains in Rails, including; generating subdomain routes, scoping resources to subdomains, and exposing subdomain information to controllers.

What I want to talk about is how I deal with subdomains in a development-environment context.

Hands off my /etc/hosts

Most of the resources I’ve seen regarding working with domain names in Rails involve manually modifying the system’s /etc/hosts file, though Eloy Duran’s PassengerPane makes it simple for those developing with Phusion Passenger.

Robby Russell calls out the gem ghost, which makes managing custom domains and subdomains drop-dead simple. The gem provides the ability to map domain names to arbitrary IPs, but in development you probably just want to map everything to the loopback address

Putting it into practice

I like to have each application manage its own domain-to-ip mappings, so I need to make sure all of the domains the application will use are accessible. How you go about this is up to you, but here’s simple example showing how to use ghost to manage four cdn hosts, the www subdomain, and the canonical domain name from config/environments/development.rb.

if hostname = ENV['RAILS_HOSTNAME']
  require 'ghost'
  cdn_domain_templates = (1..4).map { |i| 'cdn%d.%%s' % i }
  (cdn_domain_templates + [ 'www.%s', '%s' ]).each do |template|
    Host.add(template % hostname)

After starting your application in development mode, ghost will attempt to map these domain names if necessary. It escalates its permissions via sudo so you may be prompted to enter your password.

$ ghost list
Listing 6 host(s): -> -> -> ->
  -> ->

I typically leave these hostnames sitting around, but cleaning them up is as simple as issuing the command sudo ghost empty. The advantage to leaving the host entries in place is that the initial security escalation needed to establish the entries is bypassed on subsequent launches of the application.

Working in Parallels

If you use Parallels to run your application through its paces on Windows, it can be convenient to use the same domain names within the virtual machine and in OS X.

By default, virtual hosts within Parallels are set up to use Bridged Networking, causing the host to appear as a peer on the same LAN as the Mac on which it’s running. This means that in order to reach the Mac, the virtual host needs to know the Mac’s IP, which may be subject to change. To insulate yourself from this hassle, you can instead isolate the virtual host on a new subnet.

To do this, first go the Network Preferences in Parallels and enable DHCP for Shared Networking:
Parallels Global Preferences

Next, configure the virtual host to use Shared Networking:
Parallels Virtual Machine Preferences

Finally, update the virtual host’s hosts file, located at %SystemRoot%\system32\drivers\etc\ to map your application’s domains and subdomains to the IP belonging to the virtual network adapter managed by Parallels.

Configure Hosts

Now you should be able to access your application by hostname from the virtual host and can therefore copy and paste URLs between environments.

Leave a Comment

Enclose code in <code lang="ruby"></code> if you care.
Preview your comment using the button below.