Sorry. But no.
RDBMSes make poor tools for complex domain logic, business-rules, etc. If your solution to "my database and business-logic are too tightly coupled" is to move more of that business-logic into the database, "you're using your RDBMS wrong".
RDBMSes are near impossible to test. They have no source-control, no collaboration models (pull-reviews, CI/CD). They have no deployment strategies. Lack distribution.
Which is why in e.g. Rails all business logic is in the models, commonly and not in your DB schema.
(and with "no", I do understand that it is possible, just that accessible tools, frameworks or even books and course lack severely).
Right. Using an RDBMS "correctly" requires that you live in 1985. The result is actually better operationally (for model evolution, at least) than what living in 2022 gets you, though. If your product or service is "about" the data it captures/models in the DB, living in 1985 usually turns out to be worth the sacrifice.
The deeper problem is that because everyone uses RDBMSes wrong, the RDBMS vendors aren't being incentivized to invest into the developer-UX for the features that differentiate RDBMSes from other DBMSes. These features could give you a 2022 experience instead of a 1985 experience, but the vendors just don't care about the 2022 experience.
The exception to the incentives being analytical data warehouse services, like BigQuery and Snowflake. These companies do have these incentives, but they don't have the bandwidth to actually address them; nor do they operate on an open-core model where anyone outside the company could help them with their roadmap. (I say this in frustration; my own company is waiting on one of these vendors to implement support for arbitrary-precision integer columns that aren't actually just uint128s; and "lack of bandwidth to address features" is the common refrain I hear from them.)
And there's also the fact that the major RDBMS vendors are all stuck in a 1985 mindset, where they their primary users are analysts manually typing SQL. I still have yet to see an RDBMS whose pitch is "this database is for machines to talk to; it [literally] optimizes for the case of predictable — or even pre-registered† — queries, at the expense of efficient execution of arbitrary one-off queries." (Because, who runs arbitrarily-complex reporting queries against their service's production DB, rather than shoving those off to some other data-warehouse system? "Production DB for a service" should be its own product category.)
---
† Picture: your applications would register versioned schemas in advance with the DB, including all the static templated queries the application plans to do; and then, in exchange, the application would get persistent a set of persistent cross-connection-sharable query-handles. Rather than allowing the user to define indices, the DBMS uses the knowledge of what queries the app will perform to build whatever indices best optimize its own query plans. Multiple app-versions can be registered + connected simultaneously, as versioned-API "portals" onto different projections of the same data. Etc. You know, the same 2022 stuff you expect to be handling yourself on the business layer — but exposed as part of the first-class meta-schema of your DB.
Having two models pointing at the same table is disregarded as bad idea.
Then, validation for form data is coupled directly to the db schema, thanks to models, not separated by scenario.
Then, the json rendering part is coupled to the model, because it's "convention over configuration" and the community pushes for DRY everywhere, without concern for the cost. So now, the json api is surfacing any change to the underlying STORAGE mechanism of the data, instead of being stable.
Now, add a react + Typescript interface that so popular nowdays on top of it and the result is that an update to the DB schema causes changes in the model, in the controller, in the json view, potentially breaking typings in the frontend.
This is the most common situation in Rails applications.
Now, let's take this situation 2 years in the future:
The json produced by this app is massive, there are many more new endpoints. Each endpoint has json rendering, but DRY is a hard requirement, without evaluating the risk, so every json rendering for a given model is reused in other json rendering objects.
Now one change of the underlying storage ripples through many, many API endpoints, potentially affecting hundreds of files.
A Rails model that talks directly to an RDBMS table, does indeed couple your business logic directly to your data storage representation. I'm not arguing with that.
There are two ways to fix this, though. And most people only consider one of them.
The "software-oriented" way to fix the coupling — and the one that software developers usually reach for — is to embrace domain-driven Hexagonal architecture on the inward edge: to create a domain layer within the business layer that defines its own non-DB-synchronized domain objects; and then to write an explicit DB gateway that can be Commanded and Queried with those domain objects, where that layer translates those domain objects into relational row-tuples.
(Note that this is separate in concept from embracing Hexagonal architecture on the outward edge. Gateway abstractions + internal-domain/external-view model isolation+translation are well-suited concepts to encapsulating the different rates-of-change needs of your system vs. the external systems it interacts with. That's what the Hexagonal-architecture concept was invented for, and why MVC separates Controllers from Views.)
The "database-oriented" way to fix the coupling, is to continue to model your business domain within the DB, but to model it in a faceted, denormalized way, such that each query-schema gets its own view, and each command-schema gets its own writable view driven by a trigger + stored procedure, and the tables where data actually lives (and what columns/types/indices they have) are an implementation detail of how those views were written. Just like in OOP, you hide the data, encapsulating it behind an API (the views.)
When your Rails models bind to these "schemas", each Rails model then inherently represents a Query-result or a Command-changeset — without having to complexify your business layer. These objects can just be your domain objects. You're getting your domain objects directly from the database, and sending them directly into the database, because the database itself contains the translation layer mapping the domain into the storage representation. Just as with the first approach, you're free to change these mappings at any time — you just add some DB schema migrations which add/update/remove the views backing the models, and re-point your models at the new views. (If you create these views using unique-per-version names, then different versions of your app can even live in peace together, with all their versioned bits-and-pieces of translation layer co-existing and being shared between where relevant.)
This makes sense and it's an idea that makes me excited, I wish there was a community drive toward that.
I do think that most Rails developer will dismiss it because some reason like "It's weird to have a Model backed by a view" or something along those lines. I wish the Rails community pushed (way) harder on dramatically increasing SQL knowledge, because it's so important to the whole framework.
Instead most of that SQL knowledge is hidden behind active record, making it incredibly hard to acquire.
There is one thing that this approach doesn't solve, and that is the inherent flaw of activerecord: having Save on the business logic entity makes it so that returning such object back from a business-logic method is dangerous, since now any other code could potentially write to the DB (and this is what usually happens due to lack of software design principles).
I suspect you are going to suggest something along the lines of "set readonly some records and command records are only used in specific spots", which could make sense!
You mean that Rails — being an MVC framework — is tightly coupled to (or defined in terms of, even!) the schema you've chosen for your business domain, as understood by your RDBMS.
If that's a problem for you, it's very likely because you're using your RDBMS wrong. (E.g., not taking advantage of abstractions like views+triggers to provide schema [API] stability atop storage [implementation] mutability.)
An RDBMS schema is an encapsulating API for your data, just like a GraphQL schema is an encapsulating API for your data. It's just not in fashion to use it as one — very likely because the spectre of "non-standard SQL" and inter-RDBMS portability has scared all the framework developers away from actually using RDBMSes for what they're for (instead using them as glorified indexed document stores.)