Today I’ve just released version 1.0.0 of my latest gem local-subdomain offering subdomain support for your development environment, out of the box.
In this post I’d like to describe my findings and motivations.
What I’d used to do
To support subdomains during development is frustrating. By default you can’t have some subdomain.localhost to just bind to localhost.
So you have to edit your /etc/hosts
file to add some fake subdomain and when you have to test another subdomain, you’d had to edit the file again and again and… well you get my point.
But then!
I’ve stubbled on the magic domain http://lvh.me which redirects all request (including subdomains) to 127.0.0.1
. This means http://some-subdomain.lvh.me:3000 redirects to 127.0.0.1
on port 3000
and let request.subdomain
to return some-subdomain
within your Rails controller.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
Why this gem?
This week I started on a side project, requiring subdomain support. I remembered that I could use http://lvh.me but when I browsed to the url it just said ERR_CONNECTION_REFUSED
After some time I remembered Rails binds the development
environment by default to localhost
which is != 127.0.0.1
where http://lvh.me is redirecting to..
So after fixing this, I remembered to have some code, that checks if you are browsing to http://localhost:3000 to redirect to http://lvh.me:3000. Just to help remember and enforce request for subdomains to go through http://lvh.me
So a gem it is!
As many developers, I don’t like to repeat myself, and decided to make the above two steps possible within a gem.
1. The before filter
The easy part was creating a module that adds a before_filter
to the controller where the module LocalSubdomain
is included. The action would check if the request is from lvh.me
and if not, redirect to it. Nothing special.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
2. The Rack::Handler
This part was kind of tricky because we have to inject our code before the boot
of Rails is triggered, to enforce the binding address localhost
to be changed to 0.0.0.0
.
After some reading about the rails initialization process and experimenting I noticed that the gems are required (and if so) executed before the Rack::Handler
is being called, which will trigger a Ruby server to be executed (WEBrick by default).
While looking at the rack/handler.rb I noticed that the method self.default
returns a Ruby server handler. Based on which Ruby server is being used, this will return a different handler.
After inspecting WEBrick’s and Puma’s rack handlers, I noticed, they both have the self.run
method with the options
argument, containing the Host
which indicates the binding address.
Here’s a stipped part of the code I used in the gem, showing how to intercept the used Ruby server (Puma, WEBrick, …) handler and extend that handler, with a custom run
method to be able to modify the options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
|
Conclusion
After finishing these two pieces, I’ve bundled them into a Gem called local-subdomain, so I don’t have to add the before_filter
and add -b 0.0.0.0
to my rails s
command.