Reputation: 201
I have done a decent amount of base RoR work, but haven't really faced much concerning scaling and running multiple applications.
I am in the process of building an application for a client that I hope to market to other users in similar industries, but I am struggling with the high level architecture. It seems unnecessary to run a completely separate instance of the application for each client, but I don't know how to load different configurations/layouts/features for the various users. I don't expect each individual application to have extremely high traffic so it seems like a waste for each to have unique a instance/database. Yet, each instance will probably require its own CSS as well as potentially a different configuration of the available functionality.
Is this something that can be done easily using subdomains? Can I load different configurations based on this? Does anyone have insight into how the 37 signals applications manage different configurations based on account?
Upvotes: 11
Views: 2411
Reputation: 2201
When we were making the same decision for our application, we considered several things...
First and foremost, we considered complexity. When you start adding multiple customers into the same database, you need to consider how you are going to segment their data. If you've written the app for one customer, you likely haven't had to worry about this too much. In many cases, these issues are rooted in the core data model, which will lead to a lot of refactoring (if not a total rewrite).
Additionally, you never escape this complexity. Especially in a business facing application, exposing one customer's data to another customer can be deadly. You'll always need to add extra code and a lot of extra testing to protect yourself from this.
Second, we considered cost. When we considered that we could run multiple customers in their own Rails instances on the same Amazon EC2 instance with their own Amazon RDS databases within the same RDS instance, the cost became very attractive. Since we have a business facing app and won't have more than 200 customers anytime soon, we're probably talking about a few thousand dollars in extra hosting costs over a 3-5 year period.
When we compared the cost vs. the complexity, we concluded that keeping everyone in their own instances was well worth the theoretical scaling issues.
The downside to this approach is that you have to make sure that you are able to keep up with maintaining, monitoring, and upgrading multiple instances. Some simple scripts and tools like Chef can go a long way here.
Upvotes: 6
Reputation: 28312
Disclaimer
Make sure you are actually able to market the application you're writing to other customers. Have you signed a contract with your customer? If so it is likely that they own the rights to the code you are writing, in which case you will be in violation of your contract.
There's a really good article on wikipedia about Multitenancy, which you should definitely read. It'll answer a lot of your questions and make you think about your strategy. My suggestion is to build your application in such a way that you can support multitenancy as it's much harder to bolt it on after the fact.
The 37s apps don't allow any customization other than the color scheme which is probably done by having a setting which changes the stylesheet. For example:
<%= stylesheet_link_tag(@tenant.style.name) %>
You would load the tenant based upon the subdomain:
before_filter :load_tenant, :if => :tenant_request?
def tenant_request?
request.subdomain.present? && !request.subdomain == 'www'
end
def load_tenant
@tenant = Tenant.find_by_name(request.subdomain)
end
If you want to be able to have functionality you can turn on and off the easiest way would probably be to add a bitmask (there's a gem for bit masks) which let you query for available reatures. This wouldn't scale past a certain number of features, but would be a good start. You'd end up with view code like:
<% if tenant.has_feature?(:messaging) %>
<li><%= link_to 'Messages', messages_url %></li>
<% end %>
Make sure that whatever choice you make that you do the simplest thing that works.
Upvotes: 3