Removing or overriding an ActiveRecord validation added by a superclass or mixin
clearance, ruby, ruby-on-rails, validation
Solution
I ended up "solving" the problem with the following hack:
- look for an error on the `:email` attribute of type `:taken`
- check if the email is unique for this account (which is the validation I wanted to do)
- remove the error if the email is unique for this account.
Sounds reasonable until you read the code and discover how I remove an error. `ActiveRecord::Errors` has no methods to remove errors once added, so I have to grab hold of it's internals and do it myself. Super duper mega ugly.
This is the code:
def validate
super
remove_spurious_email_taken_error!(errors)
end
def remove_spurious_email_taken_error!(errors)
errors.each_error do |attribute, error|
if error.attribute == :email && error.type == :taken && email_unique_for_account?
errors_hash = errors.instance_variable_get(:@errors)
if Array == errors_hash[attribute] && errors_hash[attribute].size > 1
errors_hash[attribute].delete_at(errors_hash[attribute].index(error))
else
errors_hash.delete(attribute)
end
end
end
end
def email_unique_for_account?
match = account.users.find_by_email(email)
match.nil? or match == self
end
If anyone knows of a better way, I would be very grateful.
Problem
I'm using Clearance for authentication in my Rails application. The `Clearance::User` mixin adds a couple of validations to my `User` model, but there's one of these that I would like to remove or override. What is the best way of doing this? The validation in question is ``` validates_uniqueness_of :email, :case_sensitive => false ``` which in itself isn't bad, but I would need to add `:scope => :account_id`. The problem is that if I add this to my `User` model ``` validates_uniqueness_of :email, :scope => :account_id ``` I get both validations, and the one Clearance adds is more restrictive than mine, so mine has no effect. I need to make sure that only mine runs. How do I do this?