Rails 3.0 introduced support for routing constrained by subdomains.
A subdomain can be specified explicitly, like this:
match '/' => 'home#index', :constraints => { :subdomain => 'www' }
Or a set of subdomains can be matched using a regular expression:
match '/' => 'profiles#show', :constraints => { :subdomain => /.+/ }
Finally, for greatest flexibility, router constraints can also take objects, allowing custom code.
Create a class like this:
lib/subdomain.rb
class Subdomain def self.matches?(request) case request.subdomain when 'www', '', nil false else true end end end
This class allows use of a route when a subdomain is present in the request object. If the subdomain is “www,” the class will respond as if a subdomain is not present.
Make sure the class is autoloaded when the application starts. You can require 'subdomain'
at the top of the config/routes.rb file. Or you can modify the file config/application.rb (recommended):
# config.autoload_paths += %W(#{config.root}/extras) config.autoload_paths += %W(#{config.root}/lib)
Use this class when you create routes in the file config/routes.rb:
devise_for :users resources :users, :only => :show constraints(Subdomain) do match '/' => 'profiles#show' end root :to => "home#index"
A match from a “/” URL (such as http://myname.myapp.com) will route to the show
action of the Profiles
controller only when a subdomain is present. If a subdomain is not present (or is “www”), a route with less priority will be applied (in this case, a route to the index
action of the Home
controller).
Be sure to comment out (or remove) the route that was added by the Rails generator when we created the controller:
#get "profiles/show"
The rails3-mongoid-devise example app provides a home page that lists all registered users. We’ll modify the home page to add a link to each user’s profile page, using a URL with a custom subdomain.
app/views/home/index.html.haml
%h4 Home - @users.each do |user| %br/ User: #{link_to user.name, user} Profile: #{link_to root_url(:subdomain => user.name), root_url(:subdomain => user.name)}
Applications that do not use subdomains use routing helpers to generate links that either include the site’s hostname (for example, users_url
generates http://mysite.com/users
) or links that only contain a relative path (for example, users_path
generates /users
). To provide navigation between sites hosted on the subdomains and the main site, you must use URL helpers (“users_url”) not path helpers (“users_path”) because path helpers do not include a hostname. Rails 3.1 provides a way to include a subdomain as part of the hostname when generating links.
You can specify a hostname when creating a link, with the syntax:
root_url(:subdomain => @subdomain)
If you need a link to the main site (a URL without a subdomain), you can force the URL helper to drop the subdomain:
root_url(:host => request.domain)
Is there a better way to do this? Open an issue if you have a suggestion.
If you launch the application, it will be running at http://localhost:3000/ or http://0.0.0.0:3000/. However, unless you’ve made some configuration changes to your computer, you won’t be able to resolve an address that uses a subdomain, such as http://foo.localhost:3000/.
There are several complex solutions to this problem. You could set up your own domain name server on your localhost and create an A entry to catch all subdomains. You could modify your /etc/hosts file (but it won’t accommodate dynamically created subdomains). You can create a proxy auto-config file and set it up as the proxy in your web browser preferences.
There’s a far simpler solution that does not require reconfiguring your computer or web browser preferences. The developer Levi Cook registered a domain, lvh.me (short for: local virtual host me), that resolves to the localhost IP address 127.0.0.1 and supports wildcards (accommodating dynamically created subdomains).
For emulating subdomains it's possible also to use pow, once the application folder is linked with pow, then the app will respond either only with the domain (http://domain.dev) or with a subdomain and the domain (http://subdomain.domain.dev)