2013-08-22 98 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。