很好的问题。
首先,您必须将有关一个模型的某些内容暴露给另一个模型,有一种特定类型的角色(主要调查员),并且 ProjectAssignment 必须了解该“特殊情况”角色。但!它应该是跟踪该特殊状态的项目角色,因此我将向 ProjectRole 模型添加一个方法:
ProjectRole < ActiveRecord::Base
def ispi?
self.name == 'Principal Investigator'
end
end
然后,您必须弄清楚如何遍历所有 project_assignments 并确定其中是否有任何一个是主要调查员。您必须从 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
现在你必须改变你的关联,ProjectAssignment 只能有一个角色,所以
class ProjectAssignment < ActiveRecord::Base
belongs_to :project
belongs_to :user
has_one :project_role
end
因此,现在您可以放心,如果该项目已经存在 Principal Investigator,您就不能使用 project_role == Principal Investigator 添加 ProjectAssignment。
更新怎么样,您使用 project_role == PI 更新 ProjectAssignment,并且已经有另一个带有 PI 的 ProjectAssignment,验证将捕获它。
现在你如何保证至少有一个 PI?我认为这意味着任何一个项目的第一个项目分配必须是 PI。这是你必须有点hackish的地方,你必须直接在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 方法
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