2010-02-08 64 views
6

我有两个班,我想说明如下:多个关联到同一型号

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 

试图从人对象的俱乐部协会时不工作,给我一个错误。这个错误是因为当我查看SQL时正在查找club_table中的person_id。我可以通过声明多个has_one关联来解决它,但感觉这是不正确的做法。

一个人只能是一个俱乐部的总裁或副总裁。

任何人都可以就这个问题提供一些建议,我会非常感激。

回答

8

has_one条件绝不会在Rails的工作,因为据我所知。

在两个表上,您需要一个明确的has_onebelongs_to或每个“链接”的has_many。所以如果你有两个“链接”,你需要两个has_one和两个belongs_to。这就是它的工作原理。其次,我认为你应该重新考虑你的模型。你这样做的方式,一个人不能同时担任俱乐部和员工的总裁。或成为两家俱乐部的总裁。即使您现在没有这些功能,他们也可以在未来 - 现在更容易保持灵活性。

这样做的一种灵活方式是使用has_many :through和一个指定角色的中间表。换句话说:

# 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 

现在,假定ROLE_ID = 0意味着雇员,ROLE_ID = 1表示总裁和ROLE_ID = 2表示vice_president,可以使用这样的:

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 } 

其他备注:

  • 您可以使用角色表和模型对此进行补充。角色本来只是一个名字,角色会have_many关系和会员会belong_to角色。或者,您可以在成员身份中定义获取角色名称的方法(如果为0,则返回“员工”,如果是1,“总统”等)
  • 您可以在成员身份上添加验证,以便不超过1人成为总裁一个俱乐部或同一个俱乐部的同一个员工两次,后来,如果你开始获得一个人需要在两个地方的“例外情况”,那么你只需要修改你的验证。
+0

好吧,这绝对是一个更好的结构。不过,我不确定员工的工作是如何工作的。如果员工的名字是俱乐部的一部分,那么他们真的是独立的,所以我认为它不应该是会员表的一部分。顺便说一句,我已经为我们拥有的不同员工角色使用了角色模型。所以也许在Person模型中应该有一个与has_one EmployeeRole的关联,并且它给出了他们的雇员类型? – adimitri 2010-02-10 18:38:04

+0

你好!我不确定我是否明白'如果他们是俱乐部的一部分,那么'真正的独立'是什么意思'。如果你有一个包含员工角色的角色表,你可以再添加2个(“总裁”和“副总裁”),只用一件事。为什么你想让他们分开? – kikito 2010-02-10 20:40:48

+0

此应用程序适用于大学校园内的学生政府组织。他们资助了许多由学生管理的俱乐部,并拥有4个电子董事会职位(总裁,副总裁,秘书财务主任)。员工是学生政府和学生,但与俱乐部无关。所以他们可能是俱乐部电子白板和员工的一部分。 – adimitri 2010-02-10 22:09:39

0

我认为你的关联是错误的。你的方式很难派任总裁或副总裁。

我会做这样的:

class Club < ActiveRecord::Base 
    has_one :president, 
      :class_name => "Person", 
      :foreign_key => 'president_club_id' 
    has_one :vice_president, 
      :class_name => "Person", 
      :foreign_key => 'vice_president_club_id' 
end 

class Person < ActiveRecord::Base 
    belongs_to :club 
end 

现在你可以指定这样的角色:

club.president = Person.create(:name => 'Tom') 
club.vice_president = Person.create(:name => 'Andrew') 
+0

虽然这不起作用,因为那时我需要在People表中有一个president_club_id和vice_president_club_id(并且在我的实际应用中还有两个位置)。另外,我必须在Person类中拥有多个belongs_to去工作 另外一些人乐可能不是负责俱乐部,而是负责'员工',所以我想保留foreign_key的模型。 – adimitri 2010-02-08 16:30:30

0

我建议你介绍一个叫角色新模式。然后得到以下内容:

class Club 
    has_many :roles 

    def president 
    end 

    def vice_president 
    end 

end 

class Person 
    belongs_to :role 
end 

class Role 
    has_one :person 
    belongs_to :club 
end 
0

这是多态关联的经典用例。 这里是链接: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

喜欢的东西..

class Club < ActiveRecord::Base 
    belongs_to :person, :polymorphic => true 

class Person < ActiveRecord::Base 
    has_one :club, :as => :position 
+0

多态协会不会帮助解决这里的问题,因为它的多个人从相同的模型访问。多态关联适用于您的foreign_key可能是不同模型的情况。 – adimitri 2010-02-10 18:55:22