2

好的,这是我的问题。我有3种不同的模型,人物,角色,客户和商店。客户有很多商店,也可以有很多人。商店有很多人。人们有不同的角色。 1人可以在多家商店工作,他们可能在每家商店有不同的角色。Rails ActiveRecord Association

例如。乔可能是一家商店的助理经理和另一家商店的经理。我希望能够做的是通过做类似

Store.find(1).people.find(1).roles
(例如将返回'assistant manager')或

Store.find(2).people.find(1).roles
(例如将返回'manager')来拉正确的角色。这可能在ActiveRecord中做到吗?

我创建了一个表:roles_people其具有以下定义:

 
create_table :roles_people, :id => false do |t| 
     t.references :role 
     t.references :person 
     t.references :store 
     t.references :client 
end 

但我无法弄清楚如何让联想使用该表正常工作。任何人都可以将我指向正确的方向吗?

感谢

+0

是我遇到的是能够筛选基于该商店,他的人的角色的问题/她所属。 – Rich 2011-03-06 19:33:57

回答

3
class People 
    belongs_to :client 
    has_many :store_roles 
end 

class Roles 
    has_many :store_roles 
end 

class StoreRole 
    belongs_to :role 
    belongs_to :people 
    belongs_to :store 
end 

class Client 
    has_many :stores 
    has_many :people 
end 

class Store 
    belongs_to :client 
    has_many :store_roles 
    has_many :roles, :through => :store_roles 
end 

假设所有这些类从ActiveRecord::Base继承;)

你将需要设置的迁移和数据库结构,以反映这些关系。对于每个belongs_to,表格上都有一个:object_id字段,引用相应的表格ID。

您的查询将需要看起来像:

Store.find(1).roles.find(:all, :conditions => ["store_roles.person_id = ?", 1]) 

我可能会添加一个方法到店模式,使这个更容易一些:

def roles_for(person_id) 
    roles.find(:all, :conditions => ["store_roles.person_id = ?", person_id]) 
end 

这种方式可以使用找到角色:

Store.find(1).roles_for(1) 

或者,更好:

def self.roles_for(store_id, person_id) 
    Role.find(:all, :joins => :store_roles, :conditions => ["store_roles.store_id = ? AND store_roles.person_id = ?", store_id, person_id]) 
end 

这改变了我们的发现者:

Store.roles_for(1, 1) 

我要说的是,这最后一种方法是最为理想的,因为它会导致只有一个单一的查询,而其他各选项执行两个数据库查询每个角色查找(一个查找商店,一个查找person_id的角色)。当然,如果你已经有了Store对象,那么这不是什么大问题。

希望这个答案是足够的:)

+0

优秀!工作出色!非常感谢大家! – Rich 2011-03-12 04:05:09

1

我想你想要的是的has_many:通过

class Person < ActiveRecord::Base 
    has_many :roles_people 
    has_many :roles, :through => :roles_people 
end 

class Store < ActiveRecord::Base 
    has_many :roles_people 
    has_many :people, :through => roles_people 
end 

您还需要关系添加到RolePerson:

class RolePerson < ActiveRecord::Base 
    belongs_to :store 
    belongs_to :person 
    has_one :role 
end 

那是你找什么?

非常有用链接@blog.hasmanythrough.com

+0

你应该在这里解释他们需要创建一个RolePerson模型,它充当中间模型。 – 2011-03-06 21:56:08

+0

@ ryan-bigg谢谢你的建议!很长时间的听众,第一次海报。 – mattexx 2011-03-08 03:12:08

0

has_and_belongs_to_many是你的朋友。

class Person < ActiveRecord::Base 
    has_and_belongs_to_many :roles 
end 

通过这种方式,您可以通过致电Person.roles.all获取该人的所有角色。生成的查询将使用people_roles表。您也可以使用has_many :through,但必须自己为连接表创建模型类并自行维护所有关联。有时候这是必要的,有时候不是。取决于您的实际模型的复杂性。

+0

我试过了。但是,角色是特定于商店的。因此,如果我只想返回该特定商店的角色,我仍然无法这样做。例如,我有'ACME仓库'和'John Doe'作为'店铺经理'。 'John Doe'也是'ABC Foods'的'助理经理'。如果我查询商店。其中(:name =>“ABC Foods”)。people.where(:name =>“John Doe”)。角色,它应该只返回'assistant manager'而不是'Store Manager'。如果我查询极品仓库,它应该返回'商店经理',没有别的。 – Rich 2011-03-06 19:32:46

+0

然后,您必须'使用has_many:through',因为商店和人员之间的关联充满了角色属性。 – 2011-03-06 19:46:28

0

您需要people_roles改变你的表名,你可以删除这两个存储和客户端引用:

create_table :roles_people, :id => false do |t| 
    t.references :role 
    t.references :person 
    t.references :store 
end 

角色是什么,只属于人民。

然后,您需要使用has_and_belongs_to_many:

class Person < ActiveRecord::Base 
    has_many :roles 
    has_many :stores, :through => :people_roles 
end 

class Store < ActiveRecord::Base 
    has_many :roles 
    has_many :people, :through => :people_roles 
end 

比你可以查询:

Store.find(1).people.find(1).roles 
+0

我明白了,但在我的情况下,角色既属于人也属于商店。可以说你从事2份兼职工作。两者都在加油站。在一个加油站你是一名助理经理,在另一个加油站你只是一个收银员。我需要能够弄清楚你在哪个加油站所扮演的角色。 – Rich 2011-03-06 19:38:56

0

有趣的问题。你不能做到你想要的,但我想我们可以接近。 为了完整,我要回顾一下你的数据结构:

class Client 
    has_many :stores 
end 

class Store 
    has_many :people 
    has_many :roles 
end 

class Person 
    has_many :roles 
    has_many :stores 
end 

class Role 
    belongs_to :store 
    belongs_to :person 
end 

您将看到该角色不需要连接到客户端,因为这可以通俗易懂从商店中找到(我假设一个存储的是“拥有“只有一个客户)。

现在,rolepersonstore都链接,因此每个人可以在每个商店有不同的角色。 而在一个干净的方式找到这些,我会用一个辅助功能:

class Person 
    has_many :roles 
    has_many :stores 

    def roles_for(store) 
    roles.where("store_id=?", store.id) 
    end 
end 

所以你不能写类似

store.people.first.roles 

来获取该工作的第一人的角色商店。 但写这样的东西:

store.people.first.roles_for(store) 

我不希望太难。

之所以如此是因为在人的背景下( - >store.people.first)我们不再有任何关于商店的概念(我们如何到达那里)。

希望这会有所帮助。

+0

关闭!唯一的问题是,如果另一个商店有一位助理经理,则此查询将无法工作,因为两个商店都拥有“自己”的助理经理角色。因此,您的查询仍然会为可能不是该商店的助理经理的用户返回助理经理。我还应该提到,如果可能的话,我需要使用HABTM,因为人员表可能包含与任何商店无关的人(但我们不关心这些人)。 – Rich 2011-03-06 20:36:37

+0

您是否尝试过?这很奇怪。正如我写的那样,你从一个人拥有的角色集合开始,它将选择那些链接到正确商店的角色。所以它不能从另一个人身上返回一个角色。你能显示你当前的代码吗?事实上:你应该使用HABTM。 – nathanvda 2011-03-06 21:19:07