views:

82

answers:

4

I have stumbled on an interesting challenge regarding active record associations:

I have an Account model which can have multiple and different organisations attached to it (like for example a Company, a Contractor, a Person) and it also has a different role with each association (accountant, owner, viewer, etc.).

So I am not sure whats the best way to associate them.

+1  A: 

Use polymorphic association to attach different types of organisations. Something like

class Account < ActiveRecord::Base
  has_many :organizations
end

class Organization < ActiveRecord::Base
  belongs_to :account
  has_many :organizations
end

class Company < ActiveRecord::Base
  belongs_to :organization, :polymorphic => true
end

class Contractor < ActiveRecord::Base
  belongs_to :organization, :polymorphic => true
end

class Person < ActiveRecord::Base
  belongs_to :organization, :polymorphic => true
end

Just off top of my head. May need some tweaking. Regarding your role - add role_id or role string to Organization model.

Eimantas
Organisation has_many :organisations ?
Cezar
A: 

Have you had a look at Polymorphic Associations?

John Topley
yes I did but I am not sure how it all fits together
Cezar
A: 

so I think I found the best solution for this, which is to use Multi Table Inheritance, for anyone interested, here's a link http://mediumexposure.com/multiple-table-inheritance-active-record/

Cezar
+1  A: 

I'm taking Elimantas' example, corrected some logic errors. basically, you have an Account with N Organizations (which is a polymorphic model and has relation with one of Company, Contractor, etc...)

class Account < ActiveRecord::Base
  has_many :organizations
end

class Organization < ActiveRecord::Base
  belongs_to :account
  belongs_to :resource, :polymorphic => true
end

class Company < ActiveRecord::Base
  has_many :organizations, :as => :resource
end

class Contractor < ActiveRecord::Base
  has_many :organizations, :as => :resource
end

[...etc...]

EDIT: here's the same approach to manage Roles:

# just edited Account model with role.
class Account < ActiveRecord::Base
  has_many :organizations
  has_one :role
end

class Role < ActiveRecord::Base
  belongs_to :account
  belongs_to :resource, :polymorphic => true
end

class Accountant < ActiveRecord::Base
  has_one :role, :as => :resource
end

class Owner < ActiveRecord::Base
  has_one :role, :as => :resource
end

EDIT2:

thirth edit, now the relation is: Account has_many Organizations, each Organization has_one Role, an Account has_many Roles through Organizations

class Account < ActiveRecord::Base
  has_many :organizations
  has_many :roles, :through => :organizations
end

class Role < ActiveRecord::Base
  belongs_to :resource, :polymorphic => true
end

class Accountant < ActiveRecord::Base
  has_one :role, :as => :resource
end

class Owner < ActiveRecord::Base
  has_one :role, :as => :resource
end

is this right?

EDIT3: Role as non AR model:

It may depend by how many Roles you plan to have, or you may have a name:string field where specify 'Accountant', 'Owner', and so on.

if you don't plan to put Role as AR model, then you can define an integer column called 'role_id' and use a costant with an hash in the organization model:

class Organization < ActiveRecord::Base
   belongs_to :account

   ROLES={'Accountant' => 1, 'Owner' => 2 }

   # get role as literal name
   def role
      ROLES.invert[role_id]
   end
end

this way you'll have an Account with many Organizations, each of them with a specific Role regarding that specific Account.

EDIT4: code example of EDIT3 the following code is a raw example of how it might look this association:

# new account
a = Account.new(....)
# new company & organization with a role
comp = Company.create(....)
org1 = Organization.new(:role_id => 1, ....)
org1.resource = comp

# new Contractor & Organization with another role
contr = Contractor.create(....)
org2 = Organization.new(:role_id => 2, ....)
org2.resource = contr

a.organizations << org1
a.organizations << org2

# save Account, it will have 2 different organizations, each one with a specific role
a.save
apeacox
so where does the role fit into this ?
Cezar
Organization is a polymorphic model that is associated to Company, Contractor, etc... then you can re-apply the same approach to Role, which is associated to Accountant, Owner, etc...
apeacox
Hmm... the role is tide to both Account and Organisation. For example Account is an Accountant for Organisation1 and Account is an Owner for Organisation2. Not sure how this fits with your description.
Cezar
ok edited my answer adding Role, is it what you're looking for?
apeacox
no that's not it, the role should be part of the association between Account and Organisation, cause one Account can be an Accountant for 30 companies and an Owner for 4 companies at the same time.
Cezar
I don't think Role should be an AR model, I think it should be a string column. Also Accountant and Owner are values in that role column not AR models. So the way I see it the association between Account and Organisation should have that role column which defines the role of Account in regards to Organisation (which will give it certain permissions over Organisation).
Cezar
yeah the roles will be something like 3 maybe 4 types but I still see the role as being part of the relation between an account and an organisation cause imagine the following scenario: you are the owner of a company and want to hire 3 accountants so you give them all access to your company so, that way you'll have a company with 4 accounts attached to it each with different permisions also on the other side, each account can have multiple companies that it manages.
Cezar
yes, that's true ;) Role is part of that relation, because each Account is related to an Organization with a specific role.
apeacox
any idea how that might look in code ? I am not sure if the setup you've described fits
Cezar
look at EDIT3 for declaration, then EDIT4 for a *raw* example ;)
apeacox
because you define role_id in your organisation you can't have a different account share the same organisation but with a different role. am I missing something ? how do you add that organisation to a second account with a different role ?
Cezar
Organization is just a polymorphic model, a *real* organizazion could be a Company/Contractor/etc. So for each account, you can associate an Organization (ex: a Company already present in db) with a specific role. Then you could have another Account associated to the same Company (through Organization) but with a different role. Organization works like a glue between an Account and many different organizations. perharps you could want to apply some validation in Account model to avoid (wrong) duplicates (an account with 2 or more same organizations but different roles isn't too real, right?)
apeacox