One model - many DB connections in Rails? - ruby-on-rails

(using Ruby on Rails and ActiveRecord)
In short: Is there some way how a model can use different DB schema for each request?
Why I need id: I have a working intranet application working for one company but I decided I would like to offer it to other companies. The Rails way would be to add company_id to each model and alway use this scope. But making separate DB schema for each company would make much more sense. Is there some standard way how to do it?
thanks!

What would be wrong with having a separate instance of your application for each company?

Adding company_id to all the models is absolutely the way to go. What you're talking about is very difficult to manage in the long haul, and it may be tricky to ensure the correct connection is used to store the correct data.
Although layering in differentiation like that is annoying, it can be done and proven in a fairly short period of time, and after that things will be easier to manage. With named_scope it is not hard to filter using attributes like that.
The simple alternative is to deploy the application more than once, with a different database.yml for each company, where the data is isolated on the application level, not within the application.
It would be easy to do this with Passenger (mod_rails) and a bit of shell scripting.

Related

Ruby on Rails database workflow

I'm a bit of a Rails beginner, so I'm sorry if this question is easy. I'm wondering how I am supposed to modify the Rails database as a developer without letting users of the site modify data.
More information:
Let's say I am trying to create a website that lists books along with their information. I want users to be able to see these books, but not add/delete them. As a developer, I want a way to add books without using the command line (hard to edit mistakes). What's the easiest way for me to do this? Would there be any differences between the development database and a live hosted one?
I think there are a few approaches to do this.
different user roles. This technically breaks the rule of without letting users of the site modify data, but being able to differentiate between normal and admin users means you can limit who actually can add data into the database. I used cancancan as a way to authorize requests but I know there are others.
I agree doing it using the command line isn't ideal, but rails do support rake tasks. You can create a task that will handle most of the logic and all you need to do is something like
rake create_book["name here"]
This will make the process less error-prone.
Create data using rails migrations. Rails can generate the skeleton file for you, and you just ran any ActiveRecord methods. However, the main purpose of migration is to update the database schema, but they can seed the database as well. here's the example from the dcos
Would there be any differences between the development database and a live-hosted one?
Yea, they should be totally separate database instances. You don't want to have your development database be the same as the live one. This would cause major problems. Rails have a concept of environments where you can use different configurations, so you can pick and choose what database URL to use.
like #davidhu said here The best approach really is the use of authorization. If only admin can see a page to CRUD the books then you don't have to worry about normal users doing same plus it makes it easy for you as the admin to make changes or add to the collection. Add the gem (or reinvent the wheel) then Rails will take care of the rest for you.

Multi-tenant rails application: what are the pros and cons of different techniques?

I originally wrote my Ruby on Rails application for one client. Now, I am changing it so that it can be used for different clients. My end-goal is that some user (not me) can click a button and create a new project. Then all the necessary changes (new schema, new tables, handling of code) are generated without anyone needing me to edit a database.yml file or add new schema definitions. I am currently using the SCOPED access. So I have a project model and other associated models have a project_id column.
I have looked at other posts regarding multi-tenant applications in Rails. A lot of people seem to suggest creating a different schema for each new client in Postgres. For me, however, it is not much useful for a new client to have a different schema in terms of data model. Each client will have the same tables, rows, columns, etc.
My vision for each client is that my production database first has a table of different projects/clients. And each one of those tables links to a set of tables that are pretty much the same with different data. In other terms a table of tables. Or in other terms, the first table will map to a different set of data for each client that has the same structure.
Is the way I explained my vision at all similar to the way that Postgres implements different "schemas"? Does it look like nested tables? Or does Postgres have to query all the information in the database anyway? I do not currently use Postgres, but I would be willing to learn if it fits the design. If you know of database software that works with Rails that fits my needs, please do let me know.
Right now, I am using scopes to accomplish multi-tenant applications, but it does not feel scalable or clean. It does however make it very easy for a non-technical user to create a new project provided I give them fillable information. Do you know if it is possible with the multi-schema Postgres defintion to have it work automatically after a user clicks a button? And I would prefer that this be handled by Rails and not by an external script if possible? (please do advise either way)
Most importantly, do you recommend any plugins or that I should adopt a different framework for this task? I have found Rails to be limited in some cases of abstraction as above and this is the first time I have ran into a Rails-scaling issue.
Any advice related to multi-tenant applications or my situation is welcome. Any questions for clarification or additional advice are welcome as well.
Thanks,
--Dave
MSDN has a good introduction to multi-tenant data architecture.
At one end of the spectrum, you have one database per tenant ("shared nothing"). "Shared nothing" makes disaster recovery pretty simple, and has the highest degree of isolation between tenants. But it also has the highest average cost per tenant, and it supports the fewest tenants per server.
At the other end of the spectrum, you store a tenant id number in every row of every shared table ("shared everything"). "Shared everything" makes disaster recovery hard--for a single tenant, you'd have to restore just some rows in every shared table--and it has the lowest degree of isolation. (Badly formed queries can expose private data.) But it has the lowest cost per tenant, and it supports the highest number of tenants per server.
My vision for each client is that my production database first has a
table of different projects/clients. And each one of those tables
links to a set of tables that are pretty much the same with different
data. In other terms a table of tables. Or in other terms, the first
table will map to a different set of data for each client that has the
same structure.
This sounds like you're talking about one schema per tenant. Pay close attention to permissions (SQL GRANT and REVOKE statements. And ALTER DEFAULT PRIVILEGES.)
There are two railscasts on multitenancy that using scopes and subdomains and another to help with handling multiple schemas.
There is also the multitenant gem which could help with your scopes and apartment gem for handling multiple schemas.
Here is also a good presentation on multitenancy-with-rails.
Dont forget about using default scopes, while creating named scops the way you are now works it does feel like it could be done better. I came across this guide by Samuel Kadolph regarding this issue a few months ago and it looks like it could work well for your situation and have the benefit of keeping your application free of some PgSQL only features.
Basically the way he describes setting the application up involves adding the concepts of tennants to your application and then using this to scope the data at query time using the database.

Rails Basecamp style subdomains best practice

My goal is to have separate user accounts for each subdomain. Under no circumstance do I want cross-pollination between subdomains.
I've looked over Robby Russle, and DHH's thoughts (both are pre-Rails3 though).
The controller handling is pretty straight forward, my questions is about keeping the model's data separated. What's the best way to keep user1 from seeing user2's data?
Some idea's might include:
Add a subdomain_id foreign key to every model - Advantage, simple one-to-many relationship can be used to scope each model to a subdomain. - Disadvantage, this is pretty tight coupling between the data and the larger application logic, which seems inappropriate.
One-to-many :through for each model associating it with a subdomain - Advantage, no need to add a subdomain_id foreign key column to existing tables associating them with their sub domain. - Disadvantage, My gut feeling is that this is way overkill. Multiple join queries may get complicated and cross-pollination bugs may occur.
Separate applications or databases for each subdomain - Advantage, the data is completely segregated. - Disadvantage, a large number of individual applications/databases will need to be managed/updated/secured/hosted/etc.
Your idea?
Option 5. Guy Naor's Schema solution - Advantage, This just blew my mind. Mostly transparent to rails, COMPLETE data separation, only one database, works really great for applications that weren't originally designed as multi-tenant. a-mazing. - Disadvantage, need to be using Postgres, or some other database that supports schemas (I'm already using PG anyway), you'll need to iterate over existing schemas when you migrate.
Right now this seems far and away the best way. Are there any major drawbacks?.
If you're sure the object-to-subdomain relation will always be one-to-one, I would pick option 1. If objects might be related to multiple subdomains in the future you're bound to option 2. It incurs more overhead, but it's easily managed when using something like cancan.
I would stay away from option 3 for the reasons you mentioned. Rails doesn't do multiple databases well and besides, using multiple databases in one application doesn't guarantee any more security than the other options.

How to implement a subscription based DB, such as basecamp

I have developed a fully functional ruby-on-rails application which utilizes numerous mysql tables. I would like to turn this into a subscription based service but I have some general, probably basic, conceptual questions:
In a setup such as Basecamp does each user have access to her/his own (as in unique) db tables or are the tables shared with millions of users and Identified by some variable?
If this is the case how well does it scale? What would be the best db to use (mysql, oracle etc)?
If each user is given his/her own unique db tables; how is this accomplished? Is it through a rake task?
Are there any resources you would suggest (books, media, etc) that explain how to accomplish either of these methods?
Thanks!
I believe it is achieved using an overall account. Whereby the resources in your current system will be scoped by that account. i.e in your index actions something like #projects = #account.projects. Looking at basecamp I would say it scales very well! If you hit this problem then you have a good problem to solve, don't worry about it too much until then. I should image the database is a cluster but very much doubt each user has their own set of tables, that would become a nightmare to manage!
A quick google and I've found a this: http://www.robbyonrails.com/articles/2009/01/11/subdomain-accounts-with-ruby-on-rails-explained which also links to a post by DHH which looks like it explains how they did it.
There are probably newer write ups but I'm guessing they would be a great place start.
Good luck!
The tables are shared and identified to a "parent" using a foreign key value. Having separate tables per-user would be a nightmare. It's more likely that good database normalisation fixes most of these issues. To-dos are related to projects, projects are related to an account and then each account has many users.
The best db to use would be entirely up to you. If you're using rails and db migrations, you're only limited to what that interface can utilise. To begin with, go with either MySQL or PostgreSQL (my preference). They're free and there's a wealth of knowledge available for hobby projects.
I personally would not create separate tables per user
Reading the wikipedia entries on database normalisation and database design would be a good start. Following that you should read up as much as you can on good database design, perhaps even starting with the common mistakes developers make when it comes to database design.

How to turn a single-site app into a mantainable multi-site app without code changes?

It's an application that we use internally at the office that I would like to offer as a hosted service for anyone.
How can I do that without making major code changes?
The first thing that occurs to me is to have the app select which database to connect to based on the domain.
So each instance of the app would have its own database, but all instances would share the same code.
The only changes required to the code would be the database selection.
Is this approach maintainable? I've heard wordpress.com does this and that it offers a couple of advantages. I'm mainly looking to do it this way to avoid have to scope my entire set of database queries to a certain site within the same database.
Thanks!
The simplest way to do this is to clone the application, and create another server instance to handle it. This actually the way I handle multiple wordpress blogs on my server
Pro:
This process can be streamlined into a utility script.
Can be easily maintained if symlinks are used for the common code. IE: Everything but branding and some of the things in the config directory.
Cons:
- If you're using passenger it will require an apache restart for each new instance.
- Same if you're using Apache to route subdomains on different virtual hosts to different mongrel clusters.
However the better way comes from the question: Rails - Separate Database Per Subdomain
The method in the accepted answer is much more robust. It might require more changes than you're looking for, but it has all the benefits without the drawbacks of any other methods. Each new instance requires a new entry in the master database with the table name and other instance specific information. You'll also want custom rake task to build the database for each new instance.
I would suggest switching the database connection and adding a view_path based on the domain, I have posted code in this question.
I hope this helps!
I wouldn't do this with multiple databases as you mentioned. Keeping all your schemas/migrations in sync with all the db's could become painful.
I would look into simply making it a multi-tenant app where you have some sort of "Account" model and then all your existing models are scoped to it ... in other words, if this was a blog app, your Account has_many :posts, etc.
With this approach, you can identify accounts by subdomain ... have people choose their subdomain when they create an account and go from there.
It's pretty straightforward to do. If you need add billing into the mix, you might look at the SaaS Railskit (which handles all the signup and subdomain stuff) or Chargify.
You can also identify accounts Twitter-style ... with http://myapp.com/someuser

Resources