Question

Environment: Ruby 2.0.0, Rails 4.1, Windows 8.1, Devise, CanCan, Rolify all on PostgreSQL.

I am building an app that will have multiple companies sharing it. Each company will have devise admins that will manage their users. And, each company will have its own data in use. All of this is planned to share tables, isolated by company id within those tables. The app is currently working with user management and no problems. Each admin sees only interacts with only their company's users. I am about to build the MVC for the main application.

I want to take a reality check at this point. How exposed will one company be to another? What exposures will exist and how do I mitigate them? Is there another gem out there that will help me implement this? Or, is this just a really, really bad enough idea that I should isolate each company to its own image?

Was it helpful?

Solution

Properly isolating customers from each other is harder than it seems. Its not just a one time event, you will have to keep it in mind and continue to deal with it as you grow. And data segregation is just one part of the problem. All of your resources, servers, databases, caches, background workers, etc... are contended for by your customers and the actions of one customer can have an impact on your app's performance for others.

Definitely do your research on multi-tenancy techniques, but I would suggest you ultimately settle on wrapping a simple solution in an abstraction that is seamless to the rest of the app. Something like:

for_customer(1) do
  # This should return only the models visible to customer 1
  # regardless of where they live or however they are partitioned.
  MyModel.all
end

For the web case, that code can wrap controller actions via an around filter. Don't worry about implementing it crudely now, thats why you have an abstraction and partitioning code that lives in one place. As things change and you encounter problems and/or deficiencies, improve the implementation and deploy.

I work at a SaaS company with several hundred customers all getting real traffic, and there was no way we could have foreseen all of the issues we'd eventually run into in keeping customers isolated from one another. Things like passenger not correctly clearing memcached connections across process forks at startup during a seamless deployment. Or code that would correctly ensure db connections weren't shared across resque worker process forks suddenly becoming inadequate after an ActiveRecord upgrade.

Don't try to figure everything out now, just make sure this code lives in one spot and that if it changes, its not going to have a cascade effect to the rest of your app. Because you know its going to need to change.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top