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 https://lvh.me which redirects all
request (including subdomains) to 127.0.0.1
. This means https://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 https://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 https://lvh.me
is redirecting to..
So after fixing this, I remembered to have some code, that checks if you are browsing to https://localhost:3000 to redirect to https://lvh.me:3000. Just to help remember and enforce request for subdomains to go through https://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.