sql >> Base de Datos >  >> RDS >> PostgreSQL

Rails cuál es la diferencia en el índice único y valida_uniqueness_of

Aquí está la diferencia entre el índice único y las validaciones_uniqueness_of

Este es un parche para permitir que ActiveRecord identifique errores generados por db para violaciones de restricciones únicas. Por ejemplo, hace que lo siguiente funcione sin declarar valida_uniqueness_of:

create_table "users" do |t|
  t.string   "email",   null: false
end
add_index "users", ["email"], unique: true

class User < ActiveRecord::Base
end

User.create!(email: '[email protected]')
u = User.create(email: '[email protected]')
u.errors[:email]
=> "has already been taken"

Los beneficios son la velocidad, la facilidad de uso y la integridad --

Velocidad

Con este enfoque, no necesita realizar una búsqueda en la base de datos para verificar la unicidad al guardar (lo que a veces puede ser bastante lento cuando se pierde el índice -- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate.. . ). Si realmente le importa validar la unicidad, tendrá que usar las restricciones de la base de datos de todos modos para que la base de datos valide la unicidad sin importar qué y este enfoque elimina una consulta adicional. Verificar el índice dos veces no es un problema para la base de datos (se almacena en caché la segunda vez), pero guardar una base de datos de ida y vuelta desde la aplicación es una gran victoria.

Fácil de usar

Dado que debe tener restricciones de db para una verdadera singularidad de todos modos, este enfoque permitirá que todo suceda automáticamente una vez que las restricciones de db estén en su lugar. Todavía puedes usar valida_uniqueness_of si quieres.

Integridad

valids_uniqueness_of siempre ha sido un poco complicado:no puede manejar las condiciones de carrera correctamente y da como resultado excepciones que deben manejarse utilizando una lógica de manejo de errores un tanto redundante. (Consulte la sección "Concurrencia e integridad" en http://api.rubyonrails .org/classes/ActiveRecord/Validations/ClassMe... )

valida_exclusividad_de no es suficiente para asegurar la unicidad de un valor. La razón de esto es que en producción, múltiples procesos de trabajo pueden causar condiciones de carrera:

  1. Dos solicitudes simultáneas intentan crear un usuario con el mismo nombre (y queremos que los nombres de usuario sean únicos)

  2. Las solicitudes son aceptadas en el servidor por dos procesos de trabajo que ahora las procesarán en paralelo

  3. Ambas solicitudes escanean la tabla de usuarios y ven que el nombre está disponible

  4. Ambas solicitudes pasan la validación y crean un usuario con el nombre aparentemente disponible

Para una comprensión más clara, consulte esto

Si crea un índice único para una columna, significa que tiene la garantía de que la tabla no tendrá más de una fila con el mismo valor para esa columna. El uso de la validación únicamente validates_uniqueness_of en su modelo no es suficiente para imponer la unicidad porque puede haber usuarios simultáneos que intentan crear los mismos datos.

Imagina que dos usuarios intentan registrar una cuenta con el mismo correo electrónico en el que agregaste validates_uniqueness_of :email en tu modelo de usuario. Si presionan el botón "Registrarse" al mismo tiempo, Rails buscará en la tabla de usuarios ese correo electrónico y responderá que todo está bien y que está bien guardar el registro en la tabla. Rails luego guardará los dos registros en la tabla de usuarios con el mismo correo electrónico y ahora tienes un problema realmente horrible con el que lidiar.

Para evitar esto, también debe crear una restricción única en el nivel de la base de datos:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      ...
    end
    
    add_index :users, :email, unique: true
  end
end

Entonces, al crear el índice único index_users_on_email, obtiene dos beneficios muy buenos. Integridad de datos y buen rendimiento porque los índices únicos tienden a ser muy rápidos.

Si coloca único:verdadero en su tabla de publicaciones para user_id, entonces no permitirá ingresar registros duplicados con el mismo user_id.