My controller is catching the following error in a observed case
#<ActiveRecord::RecordNotUnique: Mysql2:: Error: Duplicate entry 'xyz1' for key 'abc.xyz': INSERT INTO'abc' (<insert statement which is throwing the error>
I wanted to know if there is a way to customize this exception such that it also includes the existing entry because of which the error of duplication is being thrown..
It might seem redundant to modify an existing standard error/exception, but I need it to avoid repetition of same logic in every controller to handle this error in order to fulfill the requirement as stated above.
Update 1 Expected output:
Whenever the following exception is thrown, an alternate error message has to be sent as exception which will be something like this..
{Message: "Error caused due to Duplicate entry 'xyz1' for key 'abc.xyz'", existing_abc_with_same_xyz: Abc.find_by(xyz: "xyz1"}
Something like overriding/overloading the existing error statement.
There are many locations where this error is being handled because of Abc being a nested_attribute
for many other resources... Because of which I will have to customise in every location, which I feel as redundant.
CodePudding user response:
You can use validation. It provides human readable error in the model
class Abc < ApplicationRecord
validates :xyz, uniqueness: true
end
And then customize message in locales
Also it's possible to use :message
key
validates :xyz,
uniqueness: {
message: ->(_, data) do
"Error caused due to Duplicate entry #{data[:value]} for key 'abc.xyz'. Existing Abc with same xyz: #{Abc.find_by(xyz: data[:value]}"
end
}
Please see guide
CodePudding user response:
You will need to validate with a custom validation class.
class User < ApplicationRecord
validates_with MyUniquenessValidator
end
to save yourself time and effort, your custom validation class can inherit from the standard uniqueness validator, and just overwrite the pieces you need to customize.
# my_uniqueness_validator.rb
class MyUniquenessValidator < ActiveRecord::Validations::Uniqueness
def validates_each # overwrites standard method
# in here, copy the standard method, but change the line
# where it looks for a duplicate to return the id of the duplicate
# and change the line where it says record.errors.add(...) to include the id of the
# record that is being duplicated
end
end
You can probably find the standard ActiveRecord uniqueness validator to study by opening activerecord in your editor: bundle open activerecord
and then navigate to 'lib/activerecord/validations/uniqueness.rb'. This is where to find it in Rails 7, it will be similar in Rails 5.