I have a problem with the scoped uniqueness validation in Rails for nested attributes with a parent of parent.
Background
I have a rails 4 appl
A better option in terms of performances is described below. It is tested and works just fine.
Why?
Mapping emails can consume a lot of ressources when a lot of emails are at stake, so its better to perform the scope directly with the database.
How?
Cashing the account_id in the EmailAddress model and performing a before validation method.
1) Create a migration :
change_table :email_addresses do |t|
t.references :account, index: true
end
add_index :email_addresses, [:account_id, :email], unique: true
2) Migrate
3) Update the EmailAddress model
#app/models/email_address.rb
class EmailAddress < ActiveRecord::Base
belongs_to :contact, inverse_of: :email_addresses
belongs_to :account
validates :label, presence: true
validates :contact, presence: true
validates_email_format_of :email
validates_uniqueness_of :email, allow_blank: false, scope: :account
before_validation do
self.account = contact.account if contact
end
end
I'll supply one possible solution. Not tested, but it should work, with a custom validation and an extra association.
In your Account
model:
has_many :email_addresses, through: :contacts
In your EmailAddress
model:
validate :uniqueness_of_mail
private
def uniqueness_of_mail
account = contact.account
if account.email_addresses.map(&:email).includes? email
errors.add(email, 'Contact already has this email address')
false
else
true
end
end