Use of the Account Location Plugin:
Get and install the plugin
Create the necessary database tables and fields
This assumes you have a table in the database named accounts with a field named username.
Use
Add the following to your application.rb
include AccountLocation
before_filter :find_account
protected
def find_account
@account = Account.find_by_username(account_subdomain)
end#
@account.username if @account && @account.respond_to?(:username)
@account.subdomain if @account && @account.respond_to?(:subdomain)
In your view, you can use any of these methods: account_url, account_host, and account_domain.
For example,
<%= account.domain %>
Because of what you added to your applicaion.rb file, you can also access @account anywhere in your application.
Must Read Information
Under Apache
You need to be sure you have a line such as
ServerName *.tadalist.com
Under Mac OSX Leopard(10.5)
Edit /etc/hosts by adding your aliases after the localhost (on the same line):
127.0.0.1 localhost adam.localhost susan.localhost
Then you have to clear the cached DNS entries:
sudo dscacheutil -flushcache
You need to change the account_subdomain method in account_location.rb (vendor/plugins/account_locator/lib) in order for it to work on your development machine. The request.subdomains array is only accessible in OS X by appending (0) at the end.
def account_subdomain
if ENV["RAILS_ENV"] == 'development'
request.subdomains(0).first
else
request.subdomains.first
end
end
Make sure you also restart your local Mongrel/WEBrick server.
Under Mac OS X Tiger (10.4)
If you are using WEBrick under Mac OS X, the simplest way to get this working is to edit /etc/hosts by adding your aliases after the localhost (on the same line):
127.0.0.1 localhost adam.localhost susan.localhost
Once that is done, you need to make sure that OS X will actually look for these domain names on your machine rather than going out to the Internet for them. The quickest way to do this is to open up NetInfo Manager in the utilities folder underneath the Applications folder. After opening the program, you will want to unlock by clicking the lock icon near the bottom and then entering your username/password (as an administrator) so that you can make system changes. Click on “machines” in the middle panel, and then click on localhost in the third panel. Click the duplicate button found near the top of the window, and then click on then change the name of ‘localhost copy’ to whatever you want the name to be (sub.domain.com). Whenever you get a prompt, go ahead and allow the action. Don’t change the other values (ip_address or serves). These values are found near the bottom of the window.
The other way is to make sure that lookupd checks /etc/hosts before going out to the DNS servers. Run lookupd -configuration and look at the entry for Host Configuration
LookupOrder: Cache FF NI DNS DS
_config_name: Host Configuration
LookupOrder Cache FF NI DNS DS
sudo kill -SIGUSR1 `cat /var/run/lookupd.pid`
You need to change the account_subdomain method in account_location.rb (vendor/plugins/account_locator/lib) in order for it to work on your development machine.
def account_subdomain
# Uncomment for production
#request.subdomains.first
request.subdomains(0).first
end
Under Windows
If you want to do this on Windows with Webbrick you need to edit the HOSTS file in c:\windows\system32\drivers\etc\hosts then add entries as per the following
127.0.0.1 localhost
127.0.0.1 adam.localhost
127.0.0.1 susan.localhost
Once that is setup, you can go to http://adam.localhost:3000 and test your subdomains!
When you use the localhost:3000 way, though, you need to make the following change in account_location.rb:
def account_subdomain
request.subdomains(0).first
end
Can someone provide an example of the application of this? What are the relationships of other models to the account model? Do we need to have account_id’s as foriegn keys scattered about our other models? How can you automatically change the subdomain if trying to access a child of account that does not belong to that account? Such as: fsu.myschool.com/pages/show/thispage, but thispage exits on the uf subdomain (account), how could one elegantly redirect to: uf.myschool.com/pages/show/thispage?
Functional testing with subdomains:
To test subdomain account keys, you can set the host parameter of the @request object in a functional test:
def test_example_test
@request.host = 'subdomain.local.host'
end
1 #rubyonrails IRC channel (01/20/05, 17:24). "This log citation ":http://www.loglibrary.com/dialogue/view/28 is available from loglibrary
2 For more on dynamic finders see under the heading Dynamic attribute-based finders" in the “API Documentation for ”http://wiki.rubyonrails.com/rails/pages/ActiveRecord" class="existingWikiWord">ActiveRecord
Session variables with subdomains:
Modify environment.rb to include the following:
ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS.update( :session_domain => '.example.com')
This ensures your session variables will be picked up, when traversing across subdomains. (Also be sure to note that the leading . in
'.example.com' is important.
Are you sure? For me, following this advice causes a new session to be created for every request. Omitting the leading ‘.’ makes things work as intended.
I will second that the only way I got this to work was to omit the leading ‘.’ This is on linux/lighttpd/fcgi.
And I will say that using the leading period works
Best Practices When Using Subdomains as Account Keys
What are the best practices when using this technique? From my experience, there are the following concerns:
Here are Davids comments explaining it further on Redhanded
The c variable refers to the instance of the controller that is passed to the filter when its triggered. This instance holds a reference to the request object, which again has an array of all the subdomains of which we need the first (so that we get “37signals” out of 37signals.clientsection.com).
bq. Then we have the Account model that has a subdomain field, which in the case of 37s would have “37signals”. We search for the account matching this subdomain with the dynamic finder and assign it to the instance variable account on the controller instance we got in. […]
Easy as pie.
In the above example, subdomain (or domain) is a field in the accounts table, and so find_by_subdomain is a dynamic finder2.
—-
See also RoutingSubdomains