2011-03-07 26 views
6

Tengo una tabla con id | patient_id | client_id | active. Un registro es único por patient_id, client_id, lo que significa que solo debe haber una inscripción por paciente por cliente. Normalmente haré que la clave primaria, pero en los rieles tengo id como mi clave principal.¿Falsifica una clave primaria compuesta? Rails

¿Cuál es la mejor manera de hacer cumplir esto? Validaciones?

Respuesta

8

Parece que tienes una relación de modelo:

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 

para hacer cumplir su restricción que lo haría en ActiveRecord, por lo que se obtiene retroalimentación adecuada al intentar guardar un registro que rompe la restricción. Me basta con modificar su modelo ClientPatient así:

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

tener cuidado sin embargo, ya que, si bien esto es ideal para aplicaciones de pequeña escala todavía es propensa a las posibles condiciones de carrera, como se describe aquí: http://apidock.com/rails/v3.0.5/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of en "concurrencia e integridad"

Como se describen allí, también debe agregar un índice único a la tabla en la base de datos. Esto proporcionará dos beneficios inmediatos:

  • La comprobación de validación y las búsquedas a través de este modelo basado en estos dos ID de llevará a cabo más rápidamente (ya que están indexados)
  • La restricción de unicidad se hará cumplir DB-lado, y en la rara ocurrencia de una condición de carrera no obtendrá datos malos guardados en la base de datos ... aunque los usuarios obtendrán un error de 500 servidores si no detecta el error.

En un archivo de migración añadir los siguientes:

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

Espero que esto era útil :)

Editar (solucionado algunos problemas de nomenclatura y un par de errores obvios):

Es entonces cuando muy fácil de encontrar los datos que está buscando:

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

Does: scope elige la (s) columna (s) donde debe (n) ser única (s) dentro? Por ejemplo, diciendo validates_uniqueness_of: patient_id,: scope =>: client_id. ¿Esto se traduce en "El ID del paciente debe ser único por client_id" –

+0

Sí, eso es lo que hace la opción: scope. Es esencialmente lo mismo que imponer una restricción de clave compuesta, ¿no es así? Puede tener dos ID de cliente iguales, siempre que su ID de paciente sea diferente. Y en el reverso puede tener dos ID de paciente que son iguales, pero las identificaciones del cliente no pueden coincidir. – nzifnab

+1

es: validates_uniqueness_of: patient_id,: scope =>: client_id y validates_uniqueness_of: client_id,: scope =>: patient_id lo mismo? –

1

Las validaciones funcionarían (Back them up with a unique index!), pero no hay forma de obtener una verdadera clave primaria compuesta en los Rails vainilla. Si quieres una clave primaria compuesta real, vas a necesitar una joya/complemento: composite_primary_keys es el que encontré, pero estoy seguro de que hay otros.

Espero que esto ayude!

Cuestiones relacionadas