2012-08-07 86 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