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.
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
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.
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
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
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.