rob
rob

Reputation: 2296

Rails validation, knowing which field is invalid?

i had a model which works fine.

class Product < ActiveRecord::Base
  validates_format_of :field1, with: /\A[0-9\+\-\/\s]+\Z/, allow_nil: true
  validates_format_of :field2, with: /\A[0-9\+\-\/\s]+\Z/, allow_nil: true
end

some of my entries in the database are invalid. these are older entries. i want to run a seed which find these invalid entries

Product.all.each do |product|
  next if product.valid?
  # 
end

i want to clear the attributes which are invalid. let me say, Product 1 has the value test in field1 which is invalid. now i want to clear this field, and only this.

how do i find the fields which are invalid? something like product.field1.valid?

Upvotes: 9

Views: 7182

Answers (3)

Roman Kiselenko
Roman Kiselenko

Reputation: 44370

The Rails api allows you to get the error message by the key with the ActiveModel::Errors#get method:

Product.all.each do |product|
  product.valid? # => run validation callbacks

  product.errors.messages          # => {:field1=>["cannot be nil"]}
  product.errors.get(:field1)      # => ["cannot be nil"]
  product.errors.get(:field2)      # => nil

  # `include?` and `has_key?` works too(it's aliases)
  product.errors.messages          # => {:field1=>["cannot be nil"]}
  product.errors.include?(:field1) # => true
  product.errors.include?(:field2) # => false

  # 
end

Upvotes: 8

Milind
Milind

Reputation: 5112

you can check and validate the model and its attribute using valid? and can also check for errors

Product.all.each do |product|
 if  !product.valid? and !product.errors[field1].blank?
    ##do something if product is not valid and there is error in attribute that you may want to check
 end
end

Upvotes: 0

tompave
tompave

Reputation: 12412

Doing it is easy, but there are a couple of things to keep in mind about performance:

  1. you don't want to just load all your products in memory, and iterate over them,
  2. if possible, you should not try to update them one by one.

This might be an acceptable solution:

invalid_ids = []

Product.find_each(batch_size: 200) do |product|
  if !product.valid?
    if product.errors.include?(:field_1)
      invalid_ids << product.id
    end
  end
end

Product.where(id: invalid_ids).update_all(field_1: nil)

Upvotes: 4

Related Questions