Your has_one
condition will never work in Rails, as far as I know.
You need one explicit has_one
or belongs_to
or has_many per "link", on both tables. So if you have two "links", you need two has_one
and two belongs_to
. That is how it works.
Secondly, I think you should reconsider your models. The way you are doing it, one person can not be the president of a club and an employee, at the same time. Or be the president of two clubs. Even if you don't have these right now, they can come in the future - it is easier to stay flexible right now.
A flexible way of doing this is using a has_many :through
with an intermediate table that specifies the role. In other words:
# The memberships table has a person_id, club_id and role_id, all integers
class Membership < ActiveRecord::Base
belongs_to :club
belongs_to :person
validates_presence_of :role_id
validates_numericality_of :role_id
end
class Club < ActiveRecord::Base
has_many :memberships, :dependent => :delete_all
has_many :people, :through => :memberships
end
class Person < ActiveRecord::Base
has_many :memberships, :dependent => :delete_all
has_many :clubs, :through => :memberships
end
Now, assuming that role_id=0 means employee, role_id=1 means president, and role_id=2 means vice_president, you can use it like this:
tyler = Person.find(1) # person_id is 1
other = Person.find(2) # person_id is 2
c = Club.find(1) # club_id is 1
tyler.clubs # returns all the clubs this person is "member" of
c.people # returns all the "members" of this club, no matter their role
#make tyler the president of c
tyler.memberships.create(:club_id => 1, :role_id => 1)
#make other the vicepresident of c
#but using c.memberships instead of other.memberships (works both ways)
c.memberships.create(:person_id => 2, :role_id => 1)
#find the (first) president of c
c.memberships.find_by_role_id(1).person
#find the (first) vicepresident of c
c.memberships.find_by_role_id(2).person
#find all the employees of c
c.memberships.find_all_by_role_id(0).collect { |m| m.person }
#find all the clubs of which tyler is president
tyler.memberships.find_all_by_role_id(1).collect { |m| m.club }
Additional notes:
- You could complement this with a roles table and model. Roles would have just a a name, roles would
have_many
relationships and memberships would belong_to
role. Or, you could define methods in memberships for getting the role name (if 0, it returns "employee", if 1, "president", etc
- You can add validations on memberhips so no more than 1 person can be made president of a given club, or the same employee on the same club twice. Later on, if you start getting "exceptional cases" in which a person needs to be in two places, you will just have to adapt your validations.