Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation: how to check for specific error

I know how to check an attribute for errors:

@post.errors[:title].any?

Is it possible to check which validation failed (for example "uniqueness")?

like image 781
Martin Petrov Avatar asked Dec 16 '22 09:12

Martin Petrov


2 Answers

Recently I came across a situation where I need the same thing: The user can add/edit multiple records at once from a single form.

Since at validation time not all records have been written to the database I cannot use @David's solution. To make things even more complicated it is possible that the records already existing in the database can become duplicates, which are detected by the uniqueness validator.

TL;DR: You can't check for a specific validator, but you can check for a specific error.

I'm using this:

# The record has a duplicate value in `my_attribute`, detected by custom code.
if my_attribute_is_not_unique?
  # Check if a previous uniqueness validator has already detected this:
  unless @record.errors.added?(:my_attribute, :taken)
    # No previous `:taken` error or at least a different text.
    @record.errors.add(:my_attribute, :taken) 
  end
end

Some remarks:

  • It does work with I18n, but you have to provide the same interpolation parameters to added? as the previous validator did.
  • This doesn't work if the previous validator has written a custom message instead of the default one (:taken)
like image 136
Daniel Rikowski Avatar answered Jan 06 '23 00:01

Daniel Rikowski


By "taken", I assume you mean that the title already exists in the database. I further assume that you have the following line in your Post model:

validates_uniqueness_of :title

Personally, I think that checking to see if the title is already taken by checking the validation errors is going to be fragile. @post.errors[:title] will return something like ["has already been taken"]. But what if you decide to change the error message or if you internationalize your application? I think you'd be better off writing a method to do the test:

class Post < ActiveRecord::Base
  def title_unique?
    Post.where(:title => self.title).count == 0
  end
end

Then you can test if the title is unique with @post.title_unique?. I wouldn't be surprised if there's already a Rubygem that dynamically adds a method like this to ActiveRecord models.

like image 25
David Avatar answered Jan 06 '23 00:01

David