【问题标题】:Rails ActiveRecord AssociationRails ActiveRecord 协会
【发布时间】:2011-03-06 19:10:02
【问题描述】:

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

例如。 Joe 可能是一家商店的助理经理和另一家商店的经理。我想做的是通过做类似的事情来拉出正确的角色

Store.find(1).people.find(1).roles
(例如,将返回“助理经理”)或

Store.find(2).people.find(1).roles
(例如,将返回“经理”)。这可以在 ActiveRecord 中进行吗?

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

create_table :roles_people, :id => false do |t| t.references :角色 t.references:人 t.references:存储 t.references:客户端 结尾

但是我不知道如何使用此表使关联正常工作。谁能指出我正确的方向?

谢谢

【问题讨论】:

  • 我遇到的问题是能够根据他/她所属的商店过滤该人的角色。

标签: ruby-on-rails ruby activerecord associations model-associations


【解决方案1】:
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])

我可能会在 store 模型中添加一个方法来简化此操作:

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 对象,那也没什么大不了的。

希望这个答案就足够了:)

【讨论】:

  • 太棒了!效果很好!非常感谢大家!
【解决方案2】:

我认为你想要的是 has_many :through

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

【讨论】:

  • 你应该在这里解释一下,他们也需要创建一个 RolePerson 模型,作为中间模型。
  • @ryan-bigg 感谢您的建议!长期聆听者,第一次发帖。
【解决方案3】:

has_and_belongs_to_many 是你的朋友。

class Person < ActiveRecord::Base
  has_and_belongs_to_many :roles
end

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

【讨论】:

  • 我试过了。但是,角色是特定于商店的。因此,如果我只想返回该特定商店的角色,我仍然无法这样做。例如,我有“ACME Warehouse”,“John Doe”作为“商店经理”。 “John Doe”还为“ABC Foods”工作,担任“助理经理”。如果我查询 Store.where(:name => "ABC Foods").people.where(:name => "John Doe").roles,它应该只返回 'assistant manager' 而不是 'Store Manager'。如果我查询 acme 仓库,它应该返回“商店经理”而不是别的。
  • 那么你必须use has_many :through,因为你的商店和人之间的关联已经被角色属性丰富了。
【解决方案4】:

好问题。你不能完全按照你的意愿去做,但我想我们可以接近。 为了完整起见,我将回顾一下您的数据结构:

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) 的上下文中,我们不再有任何关于商店的概念(我们是如何到达那里的)。

希望这会有所帮助。

【讨论】:

  • 关闭!唯一的问题是,如果另一家商店有助理经理,则此查询将不起作用,因为两家商店都“拥有”助理经理角色。因此,您的查询仍会为可能不是该商店助理经理的用户返回助理经理。我还应该提到,如果可能,我需要使用 HABTM,因为人员表可能包含与任何商店无关的人员(但我们不关心这些。)
  • 你试过了吗?这很奇怪。正如我写的那样,您从一个人拥有的roles 集合开始,它将选择那些链接到正确商店的那些。所以它不能从另一个人那里返回一个角色。你能显示你当前的代码吗?事实上:你应该使用 HABTM。
【解决方案5】:

您需要更改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

【讨论】:

  • 我明白,但在我的情况下,角色既属于个人,也属于商店。假设您从事 2 份兼职工作。两者都在加油站。在一个加油站你是一名助理经理,在另一个加油站你只是一名收银员。我需要能够弄清楚你在哪个加油站担任什么角色。
猜你喜欢
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多