How to remove errors in after_validation in Rails

132 Views Asked by At

I want the ability to set some values on my model to null if they fail validation. I have my model set up something like this:

class MyModel < ApplicationRecord
  attr_accessor :should_set_fields_to_null_if_invalid

  NULL_IF_INVALID_FIELDS = [:address, :phone]

  after_validation :set_fields_to_null_if_invalid, if: :should_set_fields_to_null_if_invalid
  ...
  # custom validations for address and phone
  ...

  def set_fields_to_null_if_invalid
    NULL_IF_INVALID_FIELDS.each do |attribute|
      self[attribute] = nil if errors.key?(attribute)
      errors.delete(attribute)
    end
  end
end

Basically, I am removing the error if it exists and set the attribute to null but I'm getting the following errors:

     ActiveRecord::RecordInvalid:
       Validation failed: 
     # /Users/albertjankowski/.rvm/gems/ruby-3.0.3/gems/activerecord-6.1.7.3/lib/active_record/validations.rb:80:in `raise_validation_error'
     # /Users/albertjankowski/.rvm/gems/ruby-3.0.3/gems/activerecord-6.1.7.3/lib/active_record/validations.rb:53:in `save!'

Not sure why it is still failing without a validation message. Does anyone have a suggestion on implementing this?

2

There are 2 best solutions below

0
albertski On BEST ANSWER

I was able to get it working by instead of using after_validation, I just just used validation:

  after_validation :set_fields_to_null_if_invalid, if: :should_set_fields_to_null_if_invalid

to

  validate :set_fields_to_null_if_invalid, if: :should_set_fields_to_null_if_invalid
4
Les Nightingill On

You save the record with save! which raises an exception... so your after_validation method is never executed. You could use the save method instead of save!, or else you could rescue the exception and fix the attribute values:

begin
  @my_model_instance.save!
rescue
  # fix the problematic attributes and save again
end

However, validations are normally used to inform the user that they need to fix something in their input. A better way is simply to test the address and phone attributes and fix them if they fail the test, without using ActiveRecord's validation scheme, like this:

class MyModelController < ApplicationController
  def create
    # read csv file
    @my_model = MyModel.new(...params from csv file...)
    @my_model.address = nil unless @my_model.valid_imported_address?
    @my_model.phone = nil unless @my_model.valid_imported_phone?
    @my_model.save!
  end
end

class MyModel < ApplicationRecord
  def valid_imported_address?
    # some test for compliant address, return true if acceptable
  end

  def valid_imported_phone?
    # some test for compliant phone, return true if acceptable
  end
end