Re: problems with Rails routing by hostname, e.g.:
http://www.verybigsite.com/ →
:controller => ‘sites’, :action => ‘list’
http://sanfrancisco.verybigsite.com/ →
:controller => ‘sites’, :action => ‘show’, :id => ‘sanfrancisco’
http://boston.verybigsite.com/ →
:controller => ‘sites’, :action => ‘show’, :id => ‘boston’
I really wanted to make this work in routing, not in URL rewriting,
before_filters, etc. Here’s my understanding of the problem, and
my simple but kludgy solution (suggestions welcomed!).
(running current versions of lighttpd, fastcgi, and rails)
First of all, lighttpd doesn’t seem to pass the useful bits of the
HTTP request header in environment variables. Or perhaps FastCGI
doesn’t forward them along to Rails. This might be a configuration
problem.
Anyway, Rails builds the route map at startup, and (in development
mode ONLY) before each request. The CGI request is fully parsed
before the route is followed, but since routes are not normally
reloaded for each request, there would be no value in passing the
request data for routing decision making…so it isn’t.
So we have to do two things:
- Store the request data somewhere persistent (or pass it to
the routing code)
- Reload the routes for each request
Depending on your circumstances, this might cause an unacceptable
performance hit. My routes are lightweight, so I decided to give
it a spin. Very limited testing suggests that reloading routes
is not a big deal at all.
Here’s what I did…
A couple of small changes to dispatcher.rb (my RubyGems install
puts it in /usr/local/lib/ruby/gems/1.8/gems/rails-1.0.0/lib):
— dispatcher.rb-orig Fri Jan 13 16:37:42 2006
+++ dispatcher.rb Fri Jan 13 16:38:29 2006
@@ -34,6 +34,7 @@
def dispatch(cgi = nil, session_options =
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
if cgi ||= new_cgi(output)
request, response = ActionController::CgiRequest.new(cgi,
session_options), ActionController::CgiResponse.new(cgi)
response).out(output)
end
@@ -66,7 +67,7 @@
end
def prepare_application
unless Controllers.const_defined?(:ApplicationController)
end
And then in config/routes.rb:
hostname=ENV[‘REQUEST_HOST’]
if hostname and hostname != ‘bigsite.com’ and hostname !=
‘www.bigsite.com’
cityname = hostname.split(‘.’).first
map.connect ‘’, :controller => ‘sites’, :action => ‘show’, :id =>
cityname
else
map.connect ‘’, :controller => ‘sites’, :action => ‘list’
end
…it works. Better ideas welcomed!
Andrew