Rails by default does not add a foreign key constraint at the database level when defining a relationship[1]. And once you have a fairly large rails app that uses this default it's somewhat tricky to migrate.
Django's ORM will create DB-level foreign keys on databases/table engines that support them. But it doesn't create many other types of database-level validation (mostly just UNIQUE and NOT NULL constraints).
Some of that is compatibility reasons; not every DB Django supports would allow creating all the desired types of constraints in the DB, so Django has no choice but to ship application-layer enforcement.
You can work around that with manually-created migrations (and I've worked some places that did this, in order to get particular constraint types that were needed at the DB level), but I don't know of a good generic solution to that problem.
Django 2.2 is going with a somewhat-manual approach to allow specifying richer types of constraints, so maybe that'll lead to progress.
The rationale is that non-trivial conditions on ActiveRecord model associations can be quite dynamic (possibly implying ruby code evaluation), therefore constraints are best handled at the model level, or else the constraints would only be partially checked at the db level, or even conflicting with the models (e.g if a constraint is to be enforced based on some condition evaluated at runtime, like a simple if clause, or when using STI or polymorphism).
I have no clue what you're talking about. That's an honest statement, not trying to be confrontational.
If you have constraints that can be enforced by the DB, you simply use the DB's constraints, because the DB guarantees they're gonna work 100% of the times and your data will be correct.
If they are more dynamic or require custom business logic... well you do it on the application layer. That's what everyone does.
I mean you can probably implement your own transactions, that doesn't mean that you should. And if you do, then just admit that there's no point in using an off-the-shelf RDBMS.
Well, Rails is kind of an off-the-shelf solution to building web apps, so it makes some compromises to present a uniform process and API for some actions. One of those trade-offs is that the relationship between database tables in ActiveRecord is handled at the model/application layer instead of the database layer.
This has some benefits - it allows for a uniform definition of relationships regardless of database backend, allows for constraints that can’t be expressed by the database itself, and allows constraints to be used as a first-class concept for things like presenting error messages to users. But it also means that data integrity is not guaranteed - modifying records concurrently or outside of the application can result in a data model that’s valid according to the database schema but not according to the application model.
FWIW I exclusively use Postgres as my Rails database backend these days, and foreign key relationships are extremely easy to include in migrations. This still requires a companion definition in application code so that good error messages can be presented, but that seems acceptable to me. I’d hope that this eventually becomes the default for databases that support these keys.
I am just that crazy person that believes that default options should err on the safety/integrity/consistency side.
I also love abstractions, but abstractions can't change their underlying fundamental reality.
So I would like to be the one who makes the compromises and I'd like those compromises to be
explicit rather than implicit.
Thanks for that tidbit, I have no XP with Rails, but I would never imagine they do something so atrocious.