Convert database constraints errors into validation errors

Hi, I noticed that 90% of the times I create a database constraints, I want that error to become an ActiveRecord validation error. The remaining 10% I usually want the error to remain an exception and handle that exception in some way (usually, retry).

At this point I thought “why not integrating this support directly in ActiveRecord”? What followed was a couple of hard coding sessions as I wrote iry, a terrible proof-of-concept library that allows to declare database constraints by name and convert them to validation errors, when these arise.
Why terrible? It has to resort to some monkey patching to work, since there is no public API to achieve what I was trying to do.
Notice that the monkey-patched version patches a method that hasn’t changed since Rails 3, but there is no guarantee it will not change.

The gem currently supports only postgres

create extension if not exists "pgcrypto";

create table if not exists users (
    id uuid primary key default gen_random_uuid(),
    unique_text text unique not null default gen_random_uuid()::text
    created_at timestamp(6) not null,
    updated_at timestamp(6) not null
);
class User < ActiveRecord::Base
  include Iry

  unique_constraint :unique_text
end

user = User.create!(unique_text: "some unique text")
fail_user = User.new(unique_text: "some unique text")

success = Iry.save(fail_user)

success #=> false
fail_user.errors.details.fetch(:unique_text) #=> [{error: :taken}]

Using fail_user.save (or save!) would run the code without activating the monkey-patch, this is to avoid breaking existing code, while Iry.save (and Iry.handle_constraints) set a thread-level variable to activate the monkey-patch.

Currently it supports:

  • unique constraints
  • check constraints
  • foreign key constraints
  • exclusion constraints

What do you think about this?
Would there be any interest in integrating this in ActiveRecord?

Thanks for sharing.

There is also GitHub - Shopify/activerecord-rescue_from_duplicate: Ruby gem to rescue from MySQL, PostgreSQL and Sqlite duplicate errors and GitHub - wvanbergen/activerecord-databasevalidations: Add validations to your ActiveRecord models based on your database constraints..

The difficulty with this as you certainly noticed is to support multiple databases.

Upstreaming this sort of capability into Rails is something that is on the radar of my team, so yes, there is interest in integrating this in Active Record for Rails 7.2-ish.

Amazing, thank you for letting me know. I’m happy to contribute if you need a hand with it, but I am not a Rails contributor, so I’m afraid I might just be in the way.

The major challenge I faced was dealing with accepts_nested_attributes_for, since there is no way to determine the order in which the records will be written