2011-03-07 58 views
6

我有一張ID爲id | patient_id | client_id | active的表格。記錄是patient_id唯一的,client_id意味着每個病人每個病人只應該有一次登記。通常我會做的主鍵,但在軌道上我有id作爲我的主鍵。假一個複合主鍵? Rails

執行此操作的最佳方法是什麼?驗證?

回答

8

聽起來像是你有一個模型關係:

class Client < ActiveRecord::Base 
    has_many :patients, :through => :enrollments 
    has_many :enrollments 
end 

class ClientPatient < ActiveRecord::Base 
    belongs_to :client 
    belongs_to :patient 
end 

class Patient < ActiveRecord::Base 
    has_many :clients, :through => :enrollments 
    has_many :enrollments 
end 

執行你的約束,我會做它的ActiveRecord,讓您嘗試保存在突破約束的記錄時得到適當的反饋。我只想修改ClientPatient模型像這樣:

class Enrollment < ActiveRecord::Base 
    belongs_to :client 
    belongs_to :patient 
    validates_uniqueness_of :patient_id, :scope => :client_id 
end 

不過要小心,因爲雖然這對於小規模的應用是偉大的是這裏所描述仍然容易出現可能的競爭條件:http://apidock.com/rails/v3.0.5/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of「併發性和完整性」下

正如他們在那裏描述的那樣,您還應該爲數據庫中的表添加唯一索引。這將提供兩個直接的好處:通過基於這兩個ID的會更快地執行這一模式

  • 的驗證檢查和任何搜索(因爲他們是索引)
  • 唯一性約束將被強制執行DB-側,並且在罕見的競態條件下,您不會將錯誤的數據保存到數據庫中......儘管如果您沒有發現錯誤,用戶將得到500服務器錯誤。

在遷移文件中添加以下內容:

add_index :enrollments, [:patient_id, :client_id], :unique => true 

希望這是有幫助:)

編輯(修正了一些命名問題和幾個明顯的錯誤):

它當時非常容易找到您要查找的數據:

Client.find_by_name("Bob Smith").patients 
Patient.find_by_name("Henry Person").clients 
+0

是否:範圍選擇它必須唯一的列?例如,通過說validates_uniqueness_of:patient_id,:scope =>:client_id。這是否轉換爲「患者ID必須是唯一的每個client_id」 –

+0

是的,這就是:範圍選項所做的。它與強制執行組合鍵約束本質上是相同的,但是不是嗎?只要患者ID不同,您可以擁有兩個相同的客戶端ID。相反,您可以擁有兩個相同的患者ID,但客戶端ID無法匹配。 – nzifnab

+1

是: validates_uniqueness_of:patient_id,:scope =>:client_id和 validates_uniqueness_of:client_id,:scope =>:patient_id是否一樣? –

1

驗證會起作用(Back them up with a unique index!),但是沒有辦法在vanilla Rails中獲得真正的複合主鍵。如果你想要一個真正的複合主鍵,你將需要一個寶石/插件 - composite_primary_keys是我找到的,但我相信還有其他人。

希望這會有所幫助!