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