Skip to content

Latest commit

 

History

History
43 lines (37 loc) · 2.12 KB

filter-active-model-validation-errors.md

File metadata and controls

43 lines (37 loc) · 2.12 KB

Filter ActiveModel Validation Errors

Now that ActiveModel has a custom Errors class (as of Rails 6.1) instead of a hash, we get some useful functionality. Namely, we get a #where method that allows us to filter errors based on the attribute name, type of validation, and even properties of that validation.

Here I have created a new Book without any attributes. All of its validations are going to fail and we are going to have an ActiveModel::Errors object attached to it with several errors.

> book = Book.new
=>
#<Book:0x00000001110397a8
...
> book.valid?
=> false
> book.errors
=> #<ActiveModel::Errors [#<ActiveModel::Error attribute=added_by, type=blank, options={:message=>:required, :if=>#<Proc:0x0000000110096260 /Users/jbranchaud/.asdf/installs/ruby/3.2.2/lib/ruby/gems/3.2.0/gems/activerecord-7.2.1/lib/active_record/associations/builder/belongs_to.rb:130 (lambda)>}>, #<ActiveModel::Error attribute=title, type=blank, options={}>, #<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>, #<ActiveModel::Error attribute=author, type=blank, options={}>, #<ActiveModel::Error attribute=publication_date, type=blank, options={}>]>

Let's say I want to check for a specific validation error. I can use #where to filter down by attribute name (e.g. :title). I can filter even further by including the validation type as well (e.g. :too_short).

> book.errors.where(:title)
=>
[#<ActiveModel::Error attribute=title, type=blank, options={}>,
 #<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>]
> book.errors.where(:title, :too_short)
=> [#<ActiveModel::Error attribute=title, type=too_short, options={:count=>3}>]
> book.errors.where(:title, :too_short).first.message
=> "is too short (minimum is 3 characters)"
> book.errors.where(:title, :too_short).first.full_message
=> "Title is too short (minimum is 3 characters)"

This filtering could be used as part of conditional checks for what flash message gets displayed to the user or even what route/view gets rendered in response to the error.