Search code examples
ruby-on-railsvalidationapi-design

How to validate in Rails 5 different ActiveRecord for the same action


I'm building an authentication system in Rails5 and I have a User for which I want to check the uniqueness and correct format for the email field. I've seen that both errors throw the same exception, ActiveRecord::RecordInvalid and I'd like to know how could I manage both cases in a good and elegant way.

This would be the important part of my model User:

validates_format_of :email, with: URI::MailTo::EMAIL_REGEXP
validates_presence_of :email
validates_uniqueness_of :email

And this would be the controller:

begin
  user.save!
  render status: :created, json: { msg: 'User was created.' }
rescue ActiveRecord::RecordInvalid => err
  render status: conflict, json: { msg: err }
end

What I'd like to do is to differentiate between Uniqueness error (to return a 409) and format error (to return a 400).

I'll appreciate any comment or help about how to do this check in the better way.


Solution

  • Catching the ActiveRecord::RecordInvalid exception is not the best way to handle this case. Instead, I would suggest to run validation explicitly and checking the errors object.

    Check Rails API documentation for ActiveModel::Validations(https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-errors) and ActiveModel::Errors (https://api.rubyonrails.org/classes/ActiveModel/Errors.html).

    After running user.valid?, you can investigate user.errors object to detect exact kind of validation error. Then you can reply with different response codes as you want:

    if !user.valid?
      if user.errors[:email] == [" ... uniqueness error ..."]
        # return 409
      elsif user.errors[:email] == [" ... format error ..."]
        # return 400
      else
        # ...
      end
    else
      user.save!
      # ...
    end