Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

298
Views
¿Es posible agregar una restricción de unicidad entre dos modelos diferentes pero asociados?

Tengo los modelos Account y User . Ambos modelos tienen un atributo de email .

Una cuenta has_many :users y un usuario belongs_to :account

Me gustaría validar la unicidad del email en ambos modelos cuando se crea una Account , por lo que el correo electrónico de la Account no es válido si lo toma un User (ya que el correo electrónico de la cuenta luego se convierte en el correo electrónico del usuario administrador).

Agregué un alcance a la restricción de email en el modelo Account pero no funciona (el formulario no se rechaza).

Modelo de cuenta:

 has_many :users validates :email, uniqueness: { scope: :users, case_sensitive: false }

¿Cuál es la forma correcta de implementar esto? ¿Necesito agregar un índice a la base de datos?

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

Una validación a nivel de aplicación en realidad no garantiza la unicidad de sus datos; simplemente detecta muchos de los casos en los que los usuarios intentan ingresar duplicados y proporciona comentarios.

Entonces, si bien podría implementar ingenuamente una validación personalizada que consulte ambas tablas, ni siquiera sobrevivirá a la condición de carrera causada por un ciudadano mayor que hace doble clic o cualquier método de inserción que eluda las validaciones.

Diagrama de flujo de solicitudes paralelas de Thoughtbot

Dado que no hay forma (AFAIK) de crear índices en las tablas, es posible que desee reestructurar su dominio y agregar un "propietario" (llámelo como quiera) a la tabla de cuentas:

 class AddOwnerToAccounts < ActiveRecord::Migration[6.1] def change add_reference :accounts, :owner, null: false, foreign_key: { to_table: 'users' } end end
 class Account < ApplicationRecord has_many :users belongs_to :owner, class_name: 'User', inverse_of: :owned_accounts delegate :email, to: :owner end
 class User < ApplicationRecord belongs_to :account has_many :owned_accounts, class_name: 'Account', foreign_key: :owner_id, inverse_of: :owner end
over 4 years ago · Santiago Trujillo Report

0

Este es un método alternativo basado en una tabla separada y una asociación polimórfica:

 class CreateEmailAddresses < ActiveRecord::Migration[6.1] def change create_table :email_addresses do |t| t.string :email, unique: true t.references :entitity, polymorphic: true t.timestamps end add_index :email_addresses, [:entity_type, :entity_id], unique: true end end
 class EmailAddress < ApplicationRecord validates_uniqueness_of :email validates_uniqueness_of :entity_id, scope: :entity_type belongs_to :entity, polymorphic: true end
 class User < ApplicationRecord has_one :email_address, as: :entity, dependent: :destroy delegate :email, to: :email_address accepts_nested_attributes_for :email_address end
 class Account < ApplicationRecord has_one :email_address, as: :entity, dependent: :destroy delegate :email, to: :email_address accepts_nested_attributes_for :email_address end

Evita tener que reestructurar su dominio o crear un usuario simplemente para crear un correo electrónico, pero causará problemas con las bibliotecas de autenticación como Devise, además de la falta de una clave externa real para garantizar la integridad referencial, lo que puede generar registros huérfanos.

En mi opinión, no es una gran solución, ya que lo más probable es que cree tantos problemas como los que resuelve.

over 4 years ago · Santiago Trujillo Report

0

Esto solo se puede lograr con un método de validación personalizado .

 validate :email_unique_for_account_and_user private def email_unique_for_account_and_user if User.where(email: email).where.not(id: id).exists? || Account.where(email: email).where.not(id: id).exists? errors.add(:email, :taken) end end

En mi opinión, no es posible definir un índice único en varias tablas de bases de datos.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!