|
|
|
|
|
by philwelch
2144 days ago
|
|
Sometimes, Rails’ conventions are just wrong, though. Databases can have various constraints (uniqueness, etc.) enforced at the DB level. ActiveRecord also allows for uniqueness checks, but these are separate mechanisms. If you want to validate for uniqueness, two processes each running the same Rails app might concurrently check for uniqueness, assume validity, and then independently insert two non-unique records. At this point, your DB will throw an error. (Edit: Rails actually wraps this exception now, but if you follow the idiomatic pattern and don’t bother catching it, it just 500’s the request.) Rails is (edit: still) not wired to treat this as a uniqueness violation at all; it just has its own uniqueness validation mechanism that doesn’t even work in the most common use case for Rails. In a concurrent environment like this with a shared DB, the only way to avoid check-and-set conditions is to just try the insert and only complain about uniqueness violations when the insert fails the DB-level uniqueness check. (Edit: Rails provides a wrapped exception for this use case, but that’s certainly not the conventional Rails way of handling uniqueness validations.) Conventions are fine when those conventions work and actually enforce good practices. ActiveRecord in particular falls short of this. And without ActiveRecord, the rest of Rails doesn’t do much to distinguish itself from alternatives. It’s fine, but it’s not necessarily anything special. |
|
ActiveRecord has thrown ActiveRecord::RecordNotUnique for this and done the right thing for over 11 years (the exception definition got moved to a different file at that point so idk exactly how old it is.)
> ActiveRecord in particular falls short of this
> without ActiveRecord, the rest of Rails doesn’t do much to distinguish itself from alternatives.
Callbacks are pretty bad but it sounds like Rails went through several near-complete rewrites worth of changes since the last time you used it. There's a lot more in Rails 6 compared to Rails 2.