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.