A popular pattern in multi-tenant applications is the use of subdomains to partition tenants. This is when you have one tenant accessing your app at
tenant1.myawesomeapp.com, another at
tenant2.myawesomeapp.com, and so on.
Using subdomains for this purpose has it’s advantages and disadvantages, but that’s a different topic. I’m going to describe how to use xip.io to test subdomains in your application, as an alternative to adding an entry in /etc/hosts on each machine you are testing on and for each subdomain you are testing.
If you haven’t heard of xip.io, it is a service provided kindly by 37signals to act as a “magic domain name that provides wildcard DNS for any IP address.” So
127.0.0.1.xip.io resolves to
127.0.0.1. Nothing interesting here. The cool part is when
tenant184.108.40.206.1.xip.io resolves to
127.0.0.1 but as far as Rails is concerned the request now has a subdomain of
So let’s say we have an application with multiple
tenants, and each
tenant has their own
stuff. We might have a routes.rb with this entry.
This will hit the
StuffController. For simplicity, lets treat authentication as out-of-scope for this article.
1 2 3 4 5
All is well and good so far, but how do we test this with RSpec and Capybara? Capybara’s
visit can take either a path or a full URL. To use subdomains we need to give it a full URL, but host of this URL will need to resolve to an IP. This is where you could change the /etc/hosts file of the machine to map a subdomain to 127.0.0.1. Or you could use xip.io to do it.
1 2 3
1 2 3 4 5 6 7 8 9 10
No changes to /etc/hosts required. There is one small change you will need to make to
config/environments/test.rb, however. You need to tell it that your top level domain will be a little longer than it expects. The default is 1, for example.com, but you need to set it to 5 for 127.0.0.1.xip.io. This tells Rails to treat anything before 127.0.0.1.xip.io as a subdomain
Now, because you have made this change to test.rb, the controller spec needs to respect the fact that you have a tld_length of 5. This means that for subdomains to work in your controller spec, you need to have a request.host that is the same length as your Capybara specs. In this case it doesn’t have to be 127.0.0.1.xip.io, it could be blah.blah.blah.blah.blah.blah, as long as it had 5 dot separators.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
So there you have it, another trick to put in your toolbelt when using subdomains with Rails.