← Back to Upcase

How to implement a has many and belongs to many association in rails


(rafik bennacer) #1

I am struggling implementing this ER diagram in rails, i wonder if it is even right.
So basically what i am trying to do is :
-a person has many roles
-a role is an organization +a position
-an position/organization has many roles
-from a position/organization i can retrieve all the roles
-from a role i can retrieve the people or a person


(Daniel Collis-Puro) #2

It looks to me that “role” is essentially an extended linker table for organizations, roles and people.

class Person < ActiveRecord::Base
  has_many :roles
  has_many :organizations, through: :roles
  has_many :positions, through: roles
end
class Role < ActiveRecord::Base
  belongs_to :person       
  belongs_to :organization 
  belongs_to :position
end
class Organization < ActiveRecord::Base 
   has_many :roles
   has_many :people, through: roles
end
class Position < ActiveRecord::Base 
   has_many :roles
   has_many :people, through: roles
end

You can tell that you don’t need additional tables because all the foreign keys you’d need to relate everything are tracked in the “role” class, and it seems like it wraps up all the use cases you’ve outlined.

I’ve found that a lot of many-to-many relations benefit from “has_many :through”, because you frequently want to track metadata on the relation, or (in your case) bring together more than just two models.


(rafik bennacer) #3

this is awesome, now how can i make the model Role accept something like:
Role.create(:person=>Person.first …) instead of Role.create(:person_id=>Person.first.id …)


(Daniel Collis-Puro) #4

What’s the error you’re seeing? That should work. . .


(rafik bennacer) #5

ActiveModel::MassAssignmentSecurity::Error: Can’t mass-assign protected attributes: person


(rafik bennacer) #6

i just added :person to attr_accessible and it si working now :smile:
attr_accessible :active, :organization_id, :person_id, :position_id,:person


(Daniel Collis-Puro) #7

This is extremely relevant, but it looks like you solved it on your own.