Say I want to deploy my app as a service to several good customers, but I want my app to share the exact layout as each customer site, so it appears to be an internal app to their company and its own clients. I take thier CSS and HTML markup, and make it into a template to wrap around my app’s content.
When I took to task to replicate that functionality in Ruby on Rails, I wasn’t certain would be easily accomplished. All the tutorials I’ve read list template switching as purely CSS affairs. Using CSS to change the presentation of your site is a fine thing, but isn’t enough if you are looking to completely copy the look and feel of a client’s website with your app dropped in.
It took some thought and a little help from the community.
Previously, the system I was used to accepted a site variable passed with the login form that told which template to render. like http://myapp.com/?site=ibm
That’s ugly and really obvious to what it is doing, but what other way is there to know which template to render?
I recall setting up accounts at a handful of sites that were in the format of: http://myusername.myapp.com
This is known as using a subdomain as an account key. Luckily, there is a very simple plugin to set that up in Rails http://wiki.rubyonrails.org/rails/pages/HowToUseSubdomainsAsAccountKeys
After setting up the plugin, I’m able to access the subdomain name anywhere in the app. Good thing, because I need to access it in application.rhtml (or .haml)
<% # if there's a subdomain, render the partial of the same name -%> <% if account_subdomain -%> <% # first check to make sure account_subdomain is valid and in accounts table -%> <% @account = Account.find_by_username(account_subdomain) -%> <% unless @account.nil? -%> <%= render :partial => "layouts/"+account_subdomain %> <% else -%> <% # There's a subdomain, but it isn't valid. Render default template -%> <%= render :partial => "layouts/default" %> <% end -%> <% else -%> <%= render :partial => "layouts/default" %> <% end -%>
Notice in the above, that there are no :yield statements. That’s because :yield can live in a partial too. I’ve set up a partial for each subdomain listed in my database in app/views/layouts, and added some logic to render the default layout when a subdomain either isn’t present or is invalid.