Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

309
Vistas
Is it possible to add a uniqueness constraint accross two different but associated models?

I have the models Account and User. Both models have an email attribute.

An Account has_many :users and a User belongs_to :account

I would like to validate the uniqueness of the email accross both models when an Account is being created so the Account email is invalid if it's taken by a User (since the account email later becomes the admin user email).

I added a scope to the email constraint in the Account model but it is not working (the form is not being rejected).

Account model:

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

What is the correct way to implement this? Do I need to add an index to the DB?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

An application level validation doesn't actually guarentee the uniqueness of your data - it merely catches a lot of the cases where users try to input duplicates and provides feedback.

So while you could naively implement a custom validation that queries both tables it won't even survive the race condition caused by a double clicking senior citizen or any insertion method that circumvents validations.

Flow chart of paralell requests from Thoughtbot

Since there is no way (AFAIK) to create indices across tables so you might want to just restructure your domain and add an "owner" (call it whatever you want) to the accounts table:

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 Denunciar

0

This is an alternative method based on a separate table and a polymorphic assocation:

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

It avoids having to restructure your domain or create a user simply to create a email but will cause issues with authentication libraries such as Devise as well as lacking a real foreign key to guarentee referential integrity which can lead to orphaned records.

IMO not a great solution as it most likely will create as many problems as it solves.

over 4 years ago · Santiago Trujillo Denunciar

0

This an only be achieved with a custom validation method.

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

IMO it is not possible to define a unique index over multiple database tables.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda