I have two classes that I would like to specify as follows:
class Club < ActiveRecord::Base
belongs_to :president, :class_name => "Person", :foreign_key => "president_id"
belongs_to :vice_president,
:class_name => "Person",
:foreign_key => "vice_president_id"
end
class Person < ActiveRecord::Base
has_one :club, :conditions =>
['president_id = ? OR vice_president_id = ?', '#{self.id}', '#{self.id}']
end
This doesn't work and gives me an error when trying to get the club association from the person object. The error is because is looking for person_id in the club table when I looked at the SQL. I can get around it by declaring multiple has_one associations, but feel like this is the improper way of doing it.
A person can only be the President or Vice President of one club.
Anyone able to offer a little bit of advice on this issue, I would be very appreciative.
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:
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", etcIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With