# 1) Point *.example.com in your DNS setup to your server.
#
# 2) Setup an Apache vhost to catch the star pointer:
#
# <VirtualHost *:80>
# ServerName example.com
# ServerAlias *.example.com
# </VirtualHost>
#
# 3) Set the current account from the subdomain
class ApplicationController < ActionController::Base
before_filter :set_current_account
private
def set_current_account
@current_account = Account.find_by_subdomain!(request.subdomains.first)
end
end
# 4) Tie all top-level requests off the current account
class CustomersController < ApplicationController
def index
@customers = @current_account.customers
end
end
Luisgo
on 08 Jan 09Thank you.
Marten Veldthuis
on 08 Jan 09The modern way for step 4 would probably be by using default_scope, right?
Adam
on 08 Jan 09Sweet Thanks,
Can you make it a bit simpler next time? :o)
srboisvert
on 08 Jan 09Just a wee blog usability heads-up. Browsing with JavaScript disabled (the way I roll) nothing at all shows up for this post – not even an indicator that something isn’t showing up.
You also might want to check your error message on a JavaScript disabled form submit.
I’ll be bookmarking the code though so thanks. This is definitely something I will need.
DHH
on 08 Jan 09Marten, I wouldn’t use default_scope for this. Anchoring off the current account makes it explicit that there’s a security scope in place. I like better to follow the path of execution like this.
IMO, default scope should only be used for things like a natural order, like “updated_at DESC”.
Also added a noscript block with just a link to the code example.
Rodrigo
on 08 Jan 09Hi David,
I was thinking about that just yesterday at night and was planning to try differente approaches.
Thank you!!!
Thomas R. Koll
on 08 Jan 09Didn’t Rails move from @params to params? Cuz I usually don’t use such before_filters anymore for e.g. current_user and current_account.
just a thought…
Anonymous Coward
on 08 Jan 09Why on earth would anyone browse with JavaScript disabled? In 2009?
DHH
on 08 Jan 09Thomas, we did, so you could have the entire instance variable space to yourself. Using that space for @current_account is exactly as it was intended.
Anonymous Coward
on 08 Jan 09No more account_location?
Great stuff. Thanks!
Jon Crawford
on 08 Jan 09In my opinion, you should use the last subdomain, “request.subdomains.last” instead of the first. For our online stores at Storenvy, I’ve seen a lot of users try “www.subdomain.storenvy.com”. I’ve even seen store owners publish their links in that format. So, I figured I should just make it work for people.
I forked the Gist and added my slight alteration. http://gist.github.com/44415
Any reason why one shouldn’t do this? I noticed Basecamp redirects if you put “www” at the start of the URL. But is that necessarily better?
DHH
on 08 Jan 09Jon, I think it’s better to have one authoritative URL, so yes, I think it’s better to do the redirect, but if you don’t do that, then last could work too.
Duarte
on 08 Jan 09Thanks for posting this!
Brad
on 08 Jan 09Does anybody know how to get subdomain.localhost working for running in a local dev environment?
DHH
on 08 Jan 09Edit your hosts file. On OS X, it’s in /etc/hosts. I have:
127.0.0.1 david.basecamp.i
Then I access http://david.basecamp.i:3000/ after I start the server with script/server.
Andy
on 08 Jan 09You don’t need to bother with the ServerName *.domain.tld, apache doesn’t seem to support wildcards there, and it doesn’t matter anyway since if you’re only running one virtual host, or your wildcard domain is the first vhost loaded by apache, everything that doesn’t match another vhost will be directed to there. ServerAlias seems to support wildcards though. I’ve never needed to change the apache configuration if all the requests come into one vhost, even with NameVirtualHosts configured and enabled.
DHH
on 08 Jan 09Andy, you’re right. It’s supposed to go in the ServerAlias. I’ll update the code. You can well have multiple applications on the same web server that all respond to this, though.
Anonymous Coward
on 09 Jan 09I use lynx to view my infanets. That’s the way I roll, son.
N/A
on 09 Jan 09This page seems to have some javascript at the bottom that calls: http://twitter.com/statuses/user_timeline/37signals.json?callback=twitterCallback2&count=3
Whenever I load this page, I get the grey htauth login box saying: To view this page you need to log in to area “Twitter API” on twitter.com:80
I click cancel and the 37Signals page logs
Andy
on 09 Jan 09“You can well have multiple applications on the same web server that all respond to this, though.”
I don’t know what that means. Maybe you can put:
but (if apache doesn’t complain about this and still runs), all requests for blah.example.com will go to which ever vhost matches the ServerAliases first, /srv/1 in this case.
You need to have unique values in each ServerName and ServerAlias for each vhost, even if they are wildcards and match multiple names.
ServerName is also used to specifiy the canonical name for the server/vhost instance. Also make sure you have UseCanonicalName Off so links and names that apache might generate (like for error pages, if you aren’t sending those through your app code also) match the host header rather than the ServerName value.
This is actually why I usually set up the initial vhost to be some generic server that contains no files (or a redirect somewhere else) and create specific vhosts for each other domain that this server serves. This way, if something gets confused (say the case of an HTTP/1.0 client which doesn’t send a Host header) a request for second-vhost.example.com that ends up on first-vhost.example.com doesn’t show the content for the wrong domain. This is more of an issue with shared virtual hosting though.
DHH
on 09 Jan 09Andy, I was talking about running multiple apps from the same Apache instance. Imagine Basecamp running on example1.com and Backpack running on example2.com:
Ric
on 09 Jan 09Thanks for publishing this info, David. These sorts of svn articles (i.e. insights into how 37signals apps use rails) are great.
Erik Dungan
on 10 Jan 09So, in this example, would the basecamp home page and info pages be served with a separate VirtualHost that only responds to www.example.com?
DHH
on 10 Jan 09Erik, exactly.
rohandey
on 10 Jan 09Please keep pouring more snippets like these…..really helpful… thankyou
SuatE
on 10 Jan 09Please keep pouring more snippets like these…..really helpful… thankyou
Robby Russell
on 11 Jan 09David & all,
I decided to take this example a step further and provide a tutorial that allows you to handle scoping on accounts through subdomains and also handling a www site.
You can check out, Subdomain accounts with Ruby on Rails explained on my blog.
Alex
on 12 Jan 09David, do you maintain a list in the app of subdomains that are not allowed (e.g. www, admin, support, blog, help)? Or create dummy accounts with those names?
rubp
on 13 Jan 09wandering – In know that in some apps 37s support https - how the redirection works ? 10x.
Ben
on 14 Jan 09Alex’s question is a good one—which subdomains should be reserved?
Has anyone thought through this and created a list of subdomains a typical web app/company would want to reserve?
Does 37signals reserve Basecamp subdomains for purposes other than user accounts?
Robby Russell
on 14 Jan 09Alex/Ben,
My post here shows you how to reserve subdomains from being used by your customers.
View post here
Alex
on 14 Jan 09Cheers Robby
This discussion is closed.