2012-08-07 84 views
2

我目前正在尝试在Rails中创建一个相当简单的关联,但它比我想象的要困难得多。Rails - 3列关联表?

我有3个模型,用户,经销商和角色。用户/经销商是多对多的。用户可以有很多角色,但是它们应该是特定于经销商的 - 即用户可以在一个经销商处拥有角色经理和主管,在另一个经理处拥有经理,在另一个经理身边担任主席。

我期待的结果是我可以做user.dealer.roles(例如,对于第一个经销商),它将返回经理和主管。如果我做dealer.user.roles 也会发生同样的情况。

我班如下所示:

class User :dealer_users has_many :dealer_user_roles, :through => :dealer_users has_many :roles, :through => :dealer_user_roles end class Dealer :dealer_users has_many :dealer_user_roles, :through => :dealer_users has_many :roles, :through => :dealer_user_roles end class Role :dealer_user_roles has_many :users, :through => :dealer_users end 

的表像(绿表):

Model diagram

我尝试使用下面的代码种子数据库:

 
dealer = Dealer.where(name: Faker::Company.name).first_or_create 
user = User.where(email: Faker::Internet.email).first_or_create 
user.first_name = Faker::Name.first_name 
user.last_name = Faker::Name.last_name 
user.password = 'password' 
user.password_confirmation = 'password' 
dealer.users user.id).first.roles 1 + Random.rand(4)) 

这会导致一个错误,即:“Can not modify assoc因为它经历了多于一个的其他关联,所以'用户#角色'。“

任何人都可以通过告诉我我错在哪里,以及如何正确使用它来提供帮助吗?

回答

4

关闭我的头顶,我将其建模为:

# Table name: users 
# id   :integer not null, primary key 
# name  :string 
class User 
    has_many :employments 
    has_many :dealers, :through => :employments 
    has_many :roles, :through => :employments 
end 

# Table name: dealers 
# id   :integer not null, primary key 
# name  :string 
class Dealer 
    has_many :employments 
    has_many :users, :through => :employments 
    has_many :roles, :through => :employments 
end 

# Table name: employments 
# id   :integer not null, primary key 
# user_id  :integer not null 
# dealer_id :integer not null 
class Employment 
belongs_to :dealer, :inverse_of => :employments 
belongs_to :user, :inverse_of => :employments 
has_many :roles 
scope :for_user, lambda{ |user| where(:user_id => user.id) } 
scope :for_dealer, lambda{ |dealer| where(:dealer_id => dealer.id) } 
end 

# Table name: roles 
# id    :integer not null, primary key 
# employment_id :integer not null 
# name   :string not null 
class Role 
    belongs_to :employment 
    scope :at_dealership, lambda{ |dealer| joins(:employment).where(:dealer_id => dealer.id) } 
    scope :for_employee, lambda{ |employee| joins(:employment).where(:user_id => employee.id) } 
    # alternately: 
    # scope :at_dealership, lambda{ |dealer| joins(:employment).where('employments.dealer_id = ?', dealer.id) } 
    # scope :for_employee, lambda{ |employee| joins(:employment).where('employments.user_id = ?',employee.id) } 
end 

这使得它更容易处理,而且也使他们实际上属于角色 - 用户/经销商的组合,我已经打电话就业。

然后你可以说

dealer.users.first.roles 
# or 
user.dealers.where('some condition').roles 

编辑:用示波器所有这些应该做你想要什么。

user = User.first 
dealer = user.dealers.first 

user.roles.at_dealership(dealer) 

dealer.roles.for_employee(user) 

dealer.employments.for_user(user).roles 

user.employments.for_dealer(dealer).roles 
+0

嗨 - 感谢您的回答,我以这种方式模拟了这种关系,它似乎有效。然而,经过测试,我发现dealer.user.first.roles带来了与该用户相关的所有经销商的所有角色,而不仅仅是与所选经销商相关的角色 - 这是预期的吗? – 2012-08-10 10:33:42

+0

你想要的语法永远不能用你的ActiveRecord来得到你想要的。 user.dealer会给你一个经销商,除非你以某种方式确定范围(就像我刚才对命名范围所做的那样),dealer.roles将会获得该经销商的所有角色。我编辑了这个示例,向您展示了一种Railsy获取所需数据的方式。获得你的语法的其他方法将与ActiveRecord冲突,并且很难实现。我没有测试过这个,所以你可能需要调整where()方法的内容来包含表名。 – 2012-08-21 01:15:08