Dealing with deletion, entitlement/roles, and multi-tenancy apps

Hi,

I am currently avaluating Rails as a possible candidate for replacing ASP.NET in a core application. I have come across a few issues in my prototypes which I'd like to solicit the group's collective wisdom on:

1. Deletion and selection of database data: Our application does not issue delete statements very often; usually it marks a row as deleted and then excludes this data by doing conditional selects. The reason for this is that customers have this funny habit of deleting things they don't mean to, and this allows us to come back and undelete it later.

The problem this poses for me is that I can't use say "Organization.departments.each" as-is; I either have to write a select method which takes deletion into account, or filter the iteration by each department's status. The latter is horrid as we do these selcts in tons of different ways and places. But, the former means I can't use the magic association and selection methods in nearly all cases, because exclusion of deleted-flagged data is something we do throughout the system.

In practical ue, the application does not select data flagged as deleted, so I am wondering if there is a way I can instruct the framework to add "where table.deleted=0" to its constructed SQL. For the few cases where I do manipulate deleted data, having to write the SQL manually would be OK.

2. Multi-tenancy applications: My core application serves many client organizations from a single application and database instance. As such, models and controllers are constantly checking permissions for who we are dealing with. Currently there are no cases in which a session or object will access data across multiple organizations. While I can see how to implement this in Rails, it looks the same as the way I do it in .NET, which is to say I'm still sitting there hooking up lots of plumbing in the model. I am wondering if there are any emerging patterns or idioms or other things to make this more elegant. I guess my perfect world would be one in which the framework understands this concept of tenancy more deeply and once I fire up a user session, it takes care of deciding what data that user gets. Sorry if the question is a little rambling.

3. User roles, entitlements, and preferences: Our current application has a small number of fixed roles, a very-simple entitlement scheme, and very few preferences. Customers are kicking down our doors to change all three. For instance, Role A should see Field #1, and Role B should not. But User X with Role A also has the option to decide whether she wants Field 1 displayed on a particular screen or not. So, my Views are literally overrun with if-else blocks. I am wondering if there are any good examples out there of patterns, idioms, helpers, plugins etc for doing this more elegantly.

Probably the biggest mess I have with this problem is tables of data. ASP.NET promises you nirvana with the DataGrid but then stabs you in the back when you have large datasets. Rails doesn't make a promise it can't keep which is nicer of it, but it still leaves me hand-coding lots of paginating sorting and column inclusion/exclusion code and after a full day of that I want a cigarette, and I don't smoke.

Anyway, I've still enjoyed the framework in many ways- the console and breakpoint features are great examples of "Duh!" things that make life so much nicer, and the way you work with SQL databases just makes more sense than the J2EE/.NET approaches, at least for every application I've worked with where the finer points of distrubuted transactions and ADO tricks have been unnecessary.

Thanks in advance, -cwk.

Hi,

I am currently avaluating Rails as a possible candidate for replacing ASP.NET in a core application. I have come across a few issues in my prototypes which I'd like to solicit the group's collective wisdom on:

1. Deletion and selection of database data: Our application does not issue delete statements very often; usually it marks a row as deleted and then excludes this data by doing conditional selects. The reason for this is that customers have this funny habit of deleting things they don't mean to, and this allows us to come back and undelete it later.

The problem this poses for me is that I can't use say "Organization.departments.each" as-is; I either have to write a select method which takes deletion into account, or filter the iteration by each department's status. The latter is horrid as we do these selcts in tons of different ways and places. But, the former means I can't use the magic association and selection methods in nearly all cases, because exclusion of deleted-flagged data is something we do throughout the system.

In practical ue, the application does not select data flagged as deleted, so I am wondering if there is a way I can instruct the framework to add "where table.deleted=0" to its constructed SQL. For the few cases where I do manipulate deleted data, having to write the SQL manually would be OK.

Check out Rick Olson's excellent plugin acts_as_paranoid. This should do exactly what you want.

2. Multi-tenancy applications: My core application serves many client organizations from a single application and database instance. As such, models and controllers are constantly checking permissions for who we are dealing with. Currently there are no cases in which a session or object will access data across multiple organizations. While I can see how to implement this in Rails, it looks the same as the way I do it in .NET, which is to say I'm still sitting there hooking up lots of plumbing in the model. I am wondering if there are any emerging patterns or idioms or other things to make this more elegant. I guess my perfect world would be one in which the framework understands this concept of tenancy more deeply and once I fire up a user session, it takes care of deciding what data that user gets. Sorry if the question is a little rambling.

There really is not much plumbing needed to handle this sort of thing. Just use a before_filter in your application.rb to find the current org.

@current_org = Organization.find_by_id(session[:org:id])

Then scope your queries like this

@files = @current_org.files

3. User roles, entitlements, and preferences: Our current application has a small number of fixed roles, a very-simple entitlement scheme, and very few preferences. Customers are kicking down our doors to change all three. For instance, Role A should see Field #1, and Role B should not. But User X with Role A also has the option to decide whether she wants Field 1 displayed on a particular screen or not. So, my Views are literally overrun with if-else blocks. I am wondering if there are any good examples out there of patterns, idioms, helpers, plugins etc for doing this more elegantly.

Use helpers to check field visibility for this logic and functional tests to validate that each role / preference is rendered correctly.

Probably the biggest mess I have with this problem is tables of data. ASP.NET promises you nirvana with the DataGrid but then stabs you in the back when you have large datasets. Rails doesn't make a promise it can't keep which is nicer of it, but it still leaves me hand-coding lots of paginating sorting and column inclusion/exclusion code and after a full day of that I want a cigarette, and I don't smoke.

Pagination is best handled by a case by case basis. The pagination built into rails will work fine on smaller data sets. Beyond that you need to figure out what makes sense for your particular solution.

Anyway, I've still enjoyed the framework in many ways- the console and breakpoint features are great examples of "Duh!" things that make life so much nicer, and the way you work with SQL databases just makes more sense than the J2EE/.NET approaches, at least for every application I've worked with where the finer points of distrubuted transactions and ADO tricks have been unnecessary.

Thanks in advance, -cwk.

>

Hope this helps.

1. Deletion and selection of database data: Our application does not issue delete statements very often; usually it marks a row as deleted and then excludes this data by doing conditional selects. The reason for this is that customers have this funny habit of deleting things they don't mean to, and this allows us to come back and undelete it later.

The problem this poses for me is that I can't use say "Organization.departments.each" as-is; I either have to write a select method which takes deletion into account, or filter the iteration by each department's status. The latter is horrid as we do these selcts in tons of different ways and places. But, the former means I can't use the magic association and selection methods in nearly all cases, because exclusion of deleted-flagged data is something we do throughout the system.

In practical ue, the application does not select data flagged as deleted, so I am wondering if there is a way I can instruct the framework to add "where table.deleted=0" to its constructed SQL. For the few cases where I do manipulate deleted data, having to write the SQL manually would be OK.

Look for acts_as_paranoid. You you can get what you want but think in terms of real deletion.

2. Multi-tenancy applications: My core application serves many client organizations from a single application and database instance. As such, models and controllers are constantly checking permissions for who we are dealing with. Currently there are no cases in which a session or object will access data across multiple organizations. While I can see how to implement this in Rails, it looks the same as the way I do it in .NET, which is to say I'm still sitting there hooking up lots of plumbing in the model. I am wondering if there are any emerging patterns or idioms or other things to make this more elegant. I guess my perfect world would be one in which the framework understands this concept of tenancy more deeply and once I fire up a user session, it takes care of deciding what data that user gets. Sorry if the question is a little rambling.

If you do something like:

   @user.tenant.items.find

The SELECT statement will include "items.tenant_id = user.tenenat_id" automatically.