Subdomains can be a tricky thing to work with. Here are some tips to develop and test Rails applications using them.
Develop
During development there are a few ways you can handle subdomains. If you are using the bundled webrick server, you won’t be able to access your subdomain at all.
Using lvh.me
If you are using the webrick server or something like Puma for development you can use lvh.me to access your subdomains. e.g. http://sub.lvh.me:9292/
‘lvh.me’ resolves to localhost, so this provides access to the subdomain in Rails on port 9292 (the Puma default). This is convenient but can be very slow to work with.
Editing your hosts
file
To avoid having to do a round trip to the internet you can add a record to your machine hosts file. In Unix/mac you can find it on /etc/hosts
You can add something like:
127.0.0.1 sub.virtual.local
Then you should be able to access your subdomain using the built in web server or puma by going to: (again 9292 is the port used by puma):
http://sub.virtual.local:9292/
Using Pow (Only available for Mac)
Pow makes it extremely easy to work with subdomains:
- [Install pow] (http://pow.cx/manual.html#section_1)
- Link your application
- Access the application using a subdomain e.g.
sub.app.dev
Have a look at the powder gem, it makes installing pow even easier.
Testing
Capybara needs to hit a real web-server in order to test your application. So you will have the same challenge as when accessing it on development.
CI
The easiest way is to use lvh.me' for this (as long as your CI server can resolve it).
Add a couple of methods accessible by your tests, e.g. in
spec/support/subdomains.rb`:
ruby
def switch_to_subdomain(subdomain)
# lvh.me always resolves to 127.0.0.1
Capybara.app_host = "http://#{subdomain}.lvh.me"
end
def switch_to_main_domain
# Capybara.app_host = "http://lvh.me"
end
Then in your feature test you can do:
ruby
switch_to_subdomain('sub')
Testing on your local machine
The above approach should work on your local machine as well, but it still wasteful as it is doing a round trip to lvh.me. I found it useful to do the following: First add an entry to your hosts file as described above:
127.0.0.1 sub.virtual.local
Add an environment variable (e.g. LOCAL_VIRTUAL_HOST) only available on development (e.g. using the dotenv-rails gem)
In .env
:
LOCAL_VIRTUAL_HOST = virtual.local
Then change spec/support/subdomains.rb
to look like:
ruby
def local_virtual_host
ENV['LOCAL_VIRTUAL_HOST'] || 'lvh.me'
end
def switch_to_subdomain(subdomain)
# lvh.me always resolves to 127.0.0.1
Capybara.app_host = "http://#{subdomain}.#{local_virtual_host}"
end
def switch_to_main_domain
Capybara.app_host = "http://#{local_virtual_host}"
end
This should make testing on your machine a lot faster. The only caveat with this approach is that something like *.virtual.local
in your hosts file won’t work, you have to list the subdomains one by one. But this is not a huge problem because you can usually limit the tests to a few specific known subdomains.