2013-08-22 101 views
0

我有两个表,一个用于成员,另一个用于员工,两个表都有一个名为id_number的属性,此属性不是必需的,可以为null。Rails跨模型验证

是否有可能运行验证,以确保所述的id_number的唯一性,所以,如果一个雇员中加入相同id_number作为构件,或反之亦然,这将给出一个错误。

我正在考虑编写自己的验证,但是每个实例的db都会很慢,因为有些公司每次上传数以十万计的员工。

回答

1

是的,这可能与您自己的验证。我认为你必须击中数据库,否则你永远无法检查它是否已经存在。

def your_validation 
    employee_ids = Employee.all.map(&:id_number) 
    member_ids = Member.all.map(&:id_number) 
    id = self.id_number 
    if employee_ids.include?(id) || member_ids.include?(id) 
    errors.add(:id_number, "is already taken") 
    end 
end 

我想为你的id_number添加一个索引会很好。

UPDATE:上述方法可以被改变成以下以提高性能:

def your_validation 
    employee_ids = Employee.all.map(&:id_number) 
    if employee_ids.include?(self.id_number) 
    errors.add(:id_number, "is already taken") 
    else 
    member_ids = Member.all.map(&:id_number) 
    if member_ids.include?(self.id_number) 
     errors.add(:id_number, "is already taken") 
    end 
    end 
end 

第一个是清洁器,第二个要快。但请查看大量数据库条目和基准测试工具。

+0

是的,我认为添加一个索引会显着加快速度。它看起来与我正在抨击的那个相似。唯一的事情是我相信你的工作哈哈。谢谢你,这是完美的 – TheLegend

+0

你可以改变employee_ids.include的顺序吗?和member_ids包括?...这可以提高速度,如果你有更多的成员比员工条目和vica,因为如果第一个已经找到新的id_number其他情况下永远不会执行。我会尽快更新我的答案。 – Mattherick

1

我想你会想是这样的:

def your_validation 
    if self.id_number.present? 
    if Employee.exists?(:id_number=>self.id_number) || Member.exists(:id_number=>self.id_number) 
     errors.add(:id_number, "is already taken") 
    end 
    end 
end 

,如果你对ID_NUMBER列此检查应该非常快速运行指标和相同的支票,validates_uniqueness_of将一个表中使用。当表格变大时,涉及将所有id提取到rails的解决方案将开始遇到问题。

要注意的另一件事是,如果您的应用程序一次运行多个Web服务器实例,这些类型的边检不能100%保证唯一性,因为它们受线程间的竞争影响。在这种情况下确保唯一性的唯一方法是使用内置于数据库中的设施,或者使用排除重复项(例如数据库序列)的来源自行生成id_numbers。