routing by subdomain (was: Re: [Rails] Unable to get the domain in my
routes.rb to map customroute tables per domain)
D Andrew Reynhout
reynhout at quesera.com
Fri Jan 13 22:25:38 GMT 2006
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)
+ ENV['REQUEST_HOST']=request.host ## set env variable
prepare_application
ActionController::Routing::Routes.recognize!(request).process(request, response).out(output)
end
@@ -66,7 +67,7 @@
end
def prepare_application
- ActionController::Routing::Routes.reload if Dependencies.load?
+ ActionController::Routing::Routes.reload ## force reload
prepare_breakpoint
Controllers.const_load!(:ApplicationController, "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
On Sat, Dec 31, 2005 at 05:22:04PM -0800, Nathaniel S. H. Brown wrote:
> I have two domains setup on my rails app:
>
> example.COM and example.NET
>
> I want to be able to have a case in the routes, that if the URL in the
> location bar is example.NET to use this route:
>
> if hostname.match(/NET/)
> map.connect '', :controller => 'special', :action => 'case'
> else
> map.connect '', :controller => 'default', :action => 'index'
> End
>
> That way I can have a new root URL for example.NET, but use the same
> application.
>
More information about the Rails
mailing list