2012-04-16 85 views
1

我有兩個對象Project和User,它們通過一個名爲ProjectAssignment的對象連接。 ProjectAssignments對象有一個附加字段:project_role。型號如下所示。Rails驗證一組對象

class Project < ActiveRecord::Base 
    #relationships 
    has_many :project_assignments 
    has_many :users, :through => :project_assignments 
end 

class ProjectAssignment < ActiveRecord::Base 
    belongs_to :project 
    belongs_to :user 
    belongs_to :project_role 
end 

class User 
    has_many :project_assignments 
    has_many :projects, :through => :project_assignments 
end 

我要驗證,對於給定的項目,恰好有一個項目分配在任何時候「首席研究員」的project_role。我有點不確定如何在ProjectAssignment模型中編寫驗證。如果我取消設置當前PI第一則小於1名首席研究員,如果設置一個用戶首席研究員在解封前,其他有超過1

class ProjectAssignment 
    validates :allow_exactly_one_pi 

    def require_exactly_one_pi 
    if self.project_role.name == 'Principal Investigator' and other_princ_inv_exists 
     #more than one principle investigator set => error 
    elseif was_principle_investigator 
     #no principle investigator set => error 
    end 
    end 
end 

任何建議,應如何處理?

+0

爲了澄清,您提到對於給定的項目,有一個projectassignment。如果是這種情況,那麼這不應該是一個has_one嗎?或者一個特定的項目可以有多個項目分配? – Nathan 2012-04-17 00:03:20

+0

項目可以有多個項目分配,但只有一個項目分配,其中project_role是首席研究員。 – Dan 2012-04-17 00:17:01

+0

我明白了。只是爲了挑戰你的想法,也許一個項目分配可以有很多用戶並且屬於一個項目。這樣,項目分配中的用戶就具有角色。否則,你只是將每個用戶包裝在他們自己的項目指派中 - 這真的是你想要的嗎? – Nathan 2012-04-17 00:32:10

回答

0

非常好的問題咀嚼。

首先,您必須將某個模型展示給另一個模型,其中有一種特定的角色(主要調查員),ProjectAssignment必須知道「特殊情況」角色。但!它應該是保持跟蹤特殊地位的項目中的角色,所以我的方法添加到ProjectRole型號:

ProjectRole < ActiveRecord::Base 
    def ispi? 
    self.name == 'Principal Investigator' 
    end 
end 

然後,你必須弄清楚如何遍歷所有project_asssignments,如果任何的決定他們是主要調查人員。您必須從project_assignment的實例訪問Class方法。

class ProjectAssignment < ActiveRecord::Base 
    validate :there_can_only_be_one_principal_investigator 

    def there_can_only_be_one_principal_investigator 
    error = false 
    self.class.where('project_id = ?',self.project_id).each do |p| 
     if p.project_role.ispi? 
     error = true 
     break 
     end 
    end 
    if error 
     #whatever 
    end 
    end 
end 

現在你必須改變你的協會,項目分配只能有一個角色,所以

class ProjectAssignment < ActiveRecord::Base 
    belongs_to :project 
    belongs_to :user 
    has_one :project_role 
end 

所以,現在你放心,你不能用project_role ==首席研究員添加一個項目分配,如果主體調查員已經存在該項目。

如何更新,您使用project_role == PI更新ProjectAssignment,並且已經有另一個ProjectAssignment和PI,驗證將會捕獲該更新。

現在你如何確保至少有一個PI?我認爲這意味着任何一個項目的FIRST ProjectAssignment必須是PI。這就是你必須有點冒險的地方,你必須直接在ProjectAssignment模型中公開有關ProjectRole模型的知識。

validate :there_must_be_at_least_one_principal_investigator 

def there_must_be_at_least_one_principal_investigator 
    if self.class.where('project_id = ?', self.project_id).count() == 0 AND !self.project_role_id == 1 
    #error 
    end 
end 

我真的不喜歡這個解決方案,因爲事實PI角色的ID爲1(或不管它是什麼),是另一種型號的硬編碼!爲了使它不那麼令人反感的,你可以添加一個類的方法到ProjectRole模型

class ProjectRole < ActiveRecord::Base 
    def self.piid 
    1 # or whatever it is 
    end 
end 

那麼做到這一點:

def there_must_be_at_least_one_principal_investigator 
    if self.class.where('project_id = ?', self.project_id).count() == 0 AND ! self.project_role_id == ProjectRole.piid 
    #error 
    end 
end 

現在,你如何改變主要研究者?你必須單獨做這件事,即

class ProjectAssignmentController < ApplicationController 
    def change_pi 
    @proj_assignment1 = ProjectAssignment.find(params[:orig_pi_id]) 
    @proj_assignment2 = ProjectAssignment.find(params[:new_pi_id]) 
    @proj_assignment1.project_role_id = params[:new_role_for_orig_pi].to_i 
    @proj_assignment1.save :validate=>false # it's OK, you're taking care of it below 
    @proj_assignment2.project_role_id = ProjectRole.piid 
    @proj_assignment2.save 
    end 
end 
+0

糾正我,如果我讀錯了代碼,但我認爲這只是例證我遇到的問題。必須始終有一個PI。上面的代碼在ispi時拋出一個錯誤?對於另一個項目任務是正確的。此外,我必須確保從未將主要調查員分配到項目中。如果我在項目任務驗證中強制執行這兩個規則,我永遠不能改變主要研究人員是誰的項目。 – Dan 2012-04-17 14:46:56

+0

好的,我現在更清楚地理解你的困境。我會編輯答案。 – RadBrad 2012-04-17 15:23:34

+0

好的,我添加了答案,但在發佈後,我認爲簡單的答案是您無法更改PI,只依賴驗證,您必須專門創建一些用於更改PI的UI,因爲無論你如何改變PI,在某些時候驗證都會失敗。答案的最後部分僅僅是一些僞代碼的示例,它應該可以在ProjectController中完成,而不是在ProjectAssignment控制器中完成,但我認爲你會得到基本的想法。 – RadBrad 2012-04-17 16:21:32

0

這是一個完全不同的方法,在總結格式:

1)當你創建一個新的項目,要求誰應該是PI的用戶,並建立第一個項目分配記錄,消除需要驗證是否至少有一個PI。

2)在ProjectController和您的項目編輯視圖中,創建某種「更改PI」界面,在該界面中您需要知道成爲新PI的用戶的user_id,以及project_role_id如果project_role_id爲零,則當前PI需要分配,這意味着用戶應該從項目中刪除。

這種方法將完全消除驗證!

第一個答案是一個非常有趣的練習,我不想建議有人改變他們的整個方法,我寧願只是回答最好的問題。但看到「驗證」變得有多複雜之後,我認爲最好不要依賴他們,你只需要編寫你的應用程序來確保你的條件得到滿足。

HTH