Modelling parent/child accounts with other models

I am creating an application that involves:

Accounts
People (Many people belong to one account)

..and various other models...

Companies
Projects
Services
...

I'm trying to find what the best way is to denote that any of the
non-account related model records belong to an account. So using the
tables listed above, what is the best way to show that any projects,
services, and companies created by the active account belong to that
account?

Should I use my authentication system to grab the account ID related to
the person signed in? Should I add a foreign key to all the other
models to denote that any records created belong to the active account?

It seems like most of my look-ups will be based on records relevant to
the current account. I'd greatly appreciate any tips.

Thanks,
David

If the models are always related to a single account then have Company
belongs_to account, Account has_many companies and so on. Then if you
have an account @account, the companies are @account.companies.

Colin

This has always bothered me and the best answer I've come up with is
"It depends"! There are at least three, but probably more, scenarios.

1. A "Basecamp" style application where you log in to an account (that
has people/user, invoices, companies, venders etc). Each account
appears to have it own database. How do you keep Foo's account from
seeing Bar's invoices? You must have a belongs to relation on (at
least) each major path. If you have a deeply nested structure, but use
the sane approach of shallow routing you have to deal with things like
"/invoices/2342" in the url and make sure that invoice ID 2342 belongs
to a customer that belongs to your account. That leads me to believe
that you have to have a before filter on almost everything that checks
that resource belongs to that account. That leads to the question on
what is the best way to handle that (which is one way your question
could be interpreted).

  Do make it easy on myself and put account_id in EVERY resource?
(before filter has what it needs - I have account_id in current_user)
  Do I put account_id in in the root of every major nested path and get
the root resource for any query on a child resource? (before filter
can get what it needs)

Getting the related resources is fairly easy
(current_user.account.companies or @account.companies), but that does
not stop someone from modifying the id in the url.

2. An "Accountant" type application where the user can access all the
accounts. This is probably not much different than the "Basecamp"
approach, it is just a super user that probably does not want Foo's
invoices mixed with Bar's invoices (but may want the option - which is
3) and start with account. Url modification is probably not a concern
since they have access to everything anyhow.

3. The account relations are there, but everything is mixed together
and you need filters or scopes to separate them when they need to be
separated.

This probably didn't answer your question (or mine), but the before
filter is probably the key - it controls what rules you are trying to
apply. Now we just have to get an answer to the second part of your
question. What is the most efficient way?

I still don't know what the best approach is for the "Basecamp" type
scenario.

  @resources = current_user.account.resources # for index or get many
  @resource = current_user.account.resources.find(params[:id]) # for
get one
  or
  @resource = Resource.find(params[:id])
  if !@resource.account_id?(current_user.account_id) # some method in
model that compares resource account_id = users account_id
    redirect_to "Unauthorized access"
  end

Steve

This has always bothered me and the best answer I've come up with is
"It depends"! There are at least three, but probably more, scenarios.

1. A "Basecamp" style application where you log in to an account (that
has people/user, invoices, companies, venders etc). Each account
appears to have it own database. How do you keep Foo's account from
seeing Bar's invoices? You must have a belongs to relation on (at
least) each major path. If you have a deeply nested structure, but use
the sane approach of shallow routing you have to deal with things like
"/invoices/2342" in the url and make sure that invoice ID 2342 belongs
to a customer that belongs to your account. That leads me to believe
that you have to have a before filter on almost everything that checks
that resource belongs to that account. That leads to the question on
what is the best way to handle that (which is one way your question
could be interpreted).

  Do make it easy on myself and put account_id in EVERY resource?
(before filter has what it needs - I have account_id in current_user)
  Do I put account_id in in the root of every major nested path and get
the root resource for any query on a child resource? (before filter
can get what it needs)

Getting the related resources is fairly easy
(current_user.account.companies or @account.companies), but that does
not stop someone from modifying the id in the url.

2. An "Accountant" type application where the user can access all the
accounts. This is probably not much different than the "Basecamp"
approach, it is just a super user that probably does not want Foo's
invoices mixed with Bar's invoices (but may want the option - which is
3) and start with account. Url modification is probably not a concern
since they have access to everything anyhow.

3. The account relations are there, but everything is mixed together
and you need filters or scopes to separate them when they need to be
separated.

This probably didn't answer your question (or mine), but the before
filter is probably the key - it controls what rules you are trying to
apply. Now we just have to get an answer to the second part of your
question. What is the most efficient way?

I still don't know what the best approach is for the "Basecamp" type
scenario.

  @resources = current_user.account.resources # for index or get many
  @resource = current_user.account.resources.find(params[:id]) # for
get one
  or
  @resource = Resource.find(params[:id])
  if !@resource.account_id?(current_user.account_id) # some method in
model that compares resource account_id = users account_id
    redirect_to "Unauthorized access"
  end

Steve

Sorry for double post, it said my session had timed out and didn't
think the first one went through. Don't see a way to delete the post.

This is a mailing list so once sent you cannot delete it. Otherwise
you would need access to my PC (for example) to delete it from my
inbox.

Colin

Thanks for the responses. I think my application probably matches the
Basecamp style of account handling. I think for simplicity I can keep
everything project-centric and use the accounts to show who owns which
projects

@account.projects
@account.projects.companies
@account.projects.people
@account.projects.services

people belongs_to companies
companies has_many people

I like the idea of leaving a foreign key on all resources to show who
the account belongs to. It's nice to know I can use a before filter to
handle it.

Playing around with my new model I feel like I've made a good decision
with the modeling.

If I were to make an ER diagram, I've effectively made a sandwich with
Projects on the top, all my supporting models and relationships in the
middle, and People and Accounts on the bottom. I've linked Accounts to
Projects as well.

I'll post more on my success or problems with this approach.