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?