Rails Multi Tenant SAAS application with user customizable fields - ruby-on-rails

We are building an a SAAS application. We need to allow customers to customize the fields of a certain model. They should be able to add or remove fields. This application is basically an asset management where customers should be able to customize the attributes of an asset.
We have tables for the assets. And these tables have multiple attribute tables like warranty, vendor, maintenance etc.
i.e
class Computer < ..
has_one :warranty
has_one :vendor
end
We have default set of attributes there but a customer should be able to alter the fields.
How do we achieve this?
Ok heres what I know. For Multitenancy we can use scopes, or multiple dbs or the awesome PostgreSQL's Schemas. But how do we implement custom fields for each customer.
Should we go for NoSQL? or should we use RDBMS for base tables and NoSQL for attribute tables?
Whats the right combination or solution or architecture for a scalable SAAS app with this requirement?

It depends on use cases and you are many choices. But, in my opinion, it's better to avoid using two kinds of db together when possible.
If you are not using PostgreSQL and no heavy queries needed for those attributes, ActiveRecord serialize can help. It utilize a text field to stored serialized hash and arrays. Nesting acceptable, speed slower.
If all of the attributes are one level key/value pair, say, warranty: 18 months, vendor: 123, then "hstore" is a good choice, built-in in PostgreSQL.
"hstore" is flexible and fast, but not suitable for nested hash. And there is a great gem dealing with it: https://github.com/diogob/activerecord-postgres-hstore
If nested hash, PostgreSQL "JSON" fieldtype may help. http://www.postgresql.org/docs/devel/static/functions-json.html It's new and I havn't used that before, just heard it's more stable and practical.
I think those choices should be enough to solve your problem. If they still can't do, maybe you can consider MongoDB.

You should definitely go for NoSQL like MongoDB. The base tables like user, profiles and other stuff which needs transaction processing should go in RDBMS.

Related

Data model and storage for Rails app

At the moment ’m building a web app using Ruby on Rails. I try to get my head around the data model and database part. To make it easy to understand I’ll use IFTTT as an analogy:
In the app, the user can add different recipes, for example:
Facebook — Twitter
Weather — Send email
You name it...
Of course every recipe has its own fields and options. So the user can choose multiple recipes from the library and set options to every recipe. The library of recipes is defined in code.
I have a few questions regarding this setup and would be happy if I could get some directions:
Is it smart to serialize the options of a recipe into a single database field? Every recipe has different fields and I don‘t want a database table for every recipe type.
Or is it better to create a ‘key-value’ table with all the options of all the recipes?
How to handle validation? Can Virtus come in handy?
Is a NoSQL database a good fit for these kinds of applications?
Are there best practices for these kinds of applications/data models? Any help is welcome.
Thanks!
Rens
Not sure if SO is the best place for really general questions like this but I'll take a swing
1 && 2) Personally I'd give the recipe table an action_taken field, probably as a string, and fields for all the available, resulting actions as booleans. Then the only thing you really need to be careful of is making sure the action_taken field remains uniform
3) ActiveRecord has a pretty fleshed out validation suite built in. You can validate based on presence, uniqueness, inclusion in a set of elements, etc. You can also extra validations on the database if you feel like being extra safe
4) I would use PostgreSQL, seems to be the community standard so probably the easiest to get support with if you need it
Hope this helps

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 avoid polymorphic associations

Given you have to implement a news feed like the one seen in social networks, ex facebook.
Currently I'm using a News class which has a polymorphic assocation which can be of any kind like Image, Comment, Friendship, GroupMembership, etc. Whenever an Object is created, as News is created too. It's working fine with AR(ActiveRecords) but I get into trouble when I'd switch to DM(DataMapper) or Sequel as both don't natevily support polymorphic associations and discourage it's usage.
One workaround would be to use a big SQL clause with lot's of UNIONs to merge all the different tables which should be considered as news. But this has some drawbacks, escpecially performance would be terrible.
So I wonder how to solve without polymorphic associations while still getting good performance and no other drawbacks, like having the possibility of adding meta data to a news?
Disclaimer: I'm the lead developer of Sequel.
The best way to go about it usually depends on what types of things you want to do with the data. One way to go about it is to have foreign key columns for all possible relationships:
news:
id
... (Other columns)
image_id
comment_id
friendship_id
group_membership_id
There is really no performance difference in doing things this way versus having a generic foreign key and storing a class name. For lazy loading, you just pick the one foreign key field that's not nil/NULL, and choose the appropriate association to load. For query-per-table eager loading, you just load all associations at once. This also is more flexible in that you can eagerly load using JOINs, which isn't possible with the polymorphic approach. Plus, you get the benefit of real referential integrity.
The one downside is that if you want to add more association types in the future, you need to add foreign keys to the table.
Here's a gem to maintain the referential integrity of Polymorphic Associations at the database level in Rails:
https://github.com/mkraft/fides
As of this posting there are adapters for SQLite3 and Postgresql.
Disclaimer: I wrote the gem.

How to create a user customizable database (like Zoho creator) in Rails?

I'm learning Rails, and the target of my experiments is to realize something similar to Zoho Creator, Flexlist or Mytaskhelper, i.e. an app where the user can create his own database schema and views. What's the best strategy to pursue this?
I saw something about the Entity-Attribute-Value (EAV) but I'm not sure whether it's the best strategy or if there is some support in Rails for it.
If there was any tutorial in Rails about a similar project it would be great.
Probably it's not the easiest star for learning a new language and framework, but it would be something I really plan to do since a long time.
Your best bet will be MongoDB. It is easy to learn (because the query language is JavaScript) and it provides a schema-less data store. I would create a document for each form that defines the structure of the form. Then, whenever a user submits the data, you can put the data into a generic structure and store it in a collection based on the name of the form. In MongoDB collections are like tables, but you can create them on the fly. You can also create indexes on the fly to speed searches.
The problem you are trying to solve is one of the primary use cases for document oriented databases which MongoDB is. There are several other document oriented databases out there, but in my opinion MongoDB has the best API at the moment.
Give the MongoDB Ruby tutorial a read and I am sure you will want to give it a try.
Do NOT use a relational database to do this. Creating tables on the fly will be miserable and is a security hazard, not just for your system, but for the data of your users as well. You can avoid creating tables on the fly by creating a complex schema that tracks the form structures and each field type would require its own table. Rails makes this less painful with polymorphic associations, but it definitely is not pretty.
I think it's not exactly what you want, but this http://github.com/LeonB/has_magic_columns_fork but apparently this does something similar and you may get some idea to get started.
Using a document store like mongodb or couchdb would be the best way forward, as they are schema-less.
It should be possible to generate database tables by sending DDL-statements directly to the server or by dynamical generating a migration. Then you can generate the corresponding ActiveRecord models using Class.new(ActiveRecord::Base) do ... end. In principle this should work, but it has to be done with some care. But this definitely no job for a beginner.
A second solution could be to use MongoMapper and MongoDB. My idea is to use a collection to store the rows of your table and since MongoDB is schema less you can simply add attributes.
Using EntryAttributeValue allows you to store any schema data in a set amount of tables, however the performance implications and maintenance issues this creates may very well not be worth it.
Alternately you could store your data in XML and generate an XML schema to validate against.
All "generic" solutions will have issues with foreign keys or other constraints, uless you do all of that validation in memory before storage.

RoR table inheritance?

Scenario: I have a users table in my application. I also have two subclasses of users, lets say contributors and viewers. Each user group must have an entirely different set of attributes but they both share certain user properties (login, password, name).
What is the best way to implement this using Ruby on Rails?
I think single table inheritance would leave me with too many null fields.
I think linking three tables (users, viewers, contributors) would work fine, but then when wanting to edit any information i have to do: #user.viewer, while i would love to be able to just do #viewer.
Any ideas of the best solution?
I would probably go with the three tables approach. Data integrity is king over code cleanliness.
If you want to make it look neater, put virtual attributes on the Viewer and Contributor models that make it look like the User attributes are local. You can make it a module and include it in both Viewer and Contributor models.
You can also set up an :include => :user on the default finders so that you don't get an extra query when using those fields.
I'm extremely caffeinated right now, so comment back if that doesn't make sense :)
don't compromise the database schema, make it fit best. I like the three table method. If you do the database bad, the application will have very hard to fix issues later, run slow, etc.

Resources