2011-10-13 60 views
9

我的工作具有模型UserProject,並且User可以分配給多個Project秒的應用程序,通過ProjectUser,與角色(如開發人員,設計師)。Rails 3中的has_many:通過加入+表條件/作用域

Project 
    has_many :project_users 
    has_many :users, :through => :project_users 

User 
    has_many :project_users 
    has_many :projects, :through => :project_users 

ProjectUser (user_id, project_id, role) 
    belongs_to :user 
    belongs_to :project 

我可以打電話@project.users@user.projects,但既然有不同的角色,我想成爲一個更具體一點與關係。理想情況下,我希望能夠做到以下幾點:

@project.developers 
    # returns @project.users, but only where ProjectUser.role = 'Developer' 

@project.designers << @user 
    # creates a ProjectUser for @project, @user with role 'Designer' 

@user.development_projects 
    # returns projects where @user is assigned as a 'Developer' 

@user.design_projects << @project 
    # creates a ProjectUser for @project, @user with role 'Designer' 

目前,我有以下代碼:

has_many :developers, :through => :project_users, :source => :user, 
         :class_name => "User", 
         :conditions => ['project_users.role = ?','Developer'] 

但這只是確實在獲取單向的,並且不給我別的 - 我不能建立或分配任何東西。

我試圖一些更復雜的邏輯,我認爲可能的工作,但希望得到一些指點:

has_many :developer_assignments, :source => :project_user, 
           :conditions => { :role => 'Developer' } 
has_many :developers, :through => :developer_assignments # class_name? 

有什麼建議?謝謝!

回答

1

這聽起來像你正在尋找的是RoR的single table inheritancenamed scopes的組合。

查看下面的article關於多態關聯的一個很好的例子。這應該可以幫助你達到以下:

@project.developers 
    # returns @project.users, but only where ProjectUser.role = 'Developer' 

@project.designers << @user 
    # creates a ProjectUser for @project, @user with role 'Designer' 

作用域會給你一個乾淨的方式來實現@user.development_projects但也有可能獲得<<運營商需要更多的掛羊頭賣狗肉。

12

has_many接受可定義/覆蓋關聯方法的塊。這將允許您爲<<創建自定義方法。我爲你創建了一個小例子,你可以用類似的方式創建構建。根據要求@project.developers << @user

# Project.rb 
has_many :developers, :through => :project_users, :source => :user, 
     :conditions => "project_users.role = 'developer'" do 
     def <<(developer) 
      proxy_owner.project_users.create(:role => 'developer', :user => developer) 
     end 
     end 

現在你可以添加一個新的開發你的項目有。 @project.developers爲您提供所有開發人員。

如果您有很多角色,則動態創建這些has_many語句可能會很有用。

# Project.rb 
ROLES = ['developer','contractor'] 

ROLES.each do |role|   
    self.class_eval <<-eos 
    has_many :#{role.downcase}s, :through => :project_users, :source => :user, 
      :conditions => "project_users.role = '#{role}'" do 
      def <<(user) 
       proxy_owner.project_users.create(:role => '#{role}', :user => user) 
      end 
      end 
    eos 
end 

回顧上面的一切似乎並不像做事方式軌道。範圍這應該使得構建和創建命令成爲可能,而不用重新定義所有的東西。

希望這會有所幫助!

+0

謝謝您的回答。它解決了我的問題,但並未按照我希望的方式這樣做 - 通過在「ProjectUsers」模型上使用範圍。 聲明':conditions =>「project_users.role ='#{role}'」'看起來好像不是很有道理,因爲我喜歡調用像':conditions => {:scope =>:developer}' 。我仍然肯定這是可能的。無論哪種方式,我都會獎勵你爲你付出的努力,儘管這個答案不會被標記爲正確的。感謝您的輸入! – Jeriko

+0

謝謝。我真的希望'has_many:designers,:through =>:project_users,:source =>:user,:conditions => {:project_users => {:role =>:designer}}'自動工作,但顯然是嵌套條件哈希不在構建和創建範圍內。這是我能想到的最好的。 – HectorMalot

+0

以上是什麼'proxy_owner'?是指對assiociation的另一方,類似於你用':extend'得到的'proxy_association'? – sbeam

0

您是否嘗試過使用scopes呢?它不會讓你做< <。但它簡化了查詢。

嘗試:

Project 
    scope :developers, lambda { 
    includes(:project_users).where("project_users.role = ?", "developer") 
    } 

您將能夠獲得使用所有開發人員:@project.developers