I've been building some apps with stacks lately that are supposed to be more modern and performant. Namely an app with Spring Boot and another with Micronaut. Both had a React frontend. It really made me appreciate Rails' omakase approach. Just having a form that shows validation errors from the backend and having something as simple as Rails' flash messages isn't solved by the frameworks themselves and requires you to build it yourself or find a third-party solution that might or might not do the basic thing you need or might or might not be well-supported. Rails truly solves the problems 90% of web apps share. It might not be in a way that's perfect for your specific project but it will likely work and you can swap it out one you've validated you app or feature.
It does have validations but the integration of then in Rails goes much further. In Rails you associate the form with the model and the validation errors somatically show up on the form.
The biggest difference here is that Spring Boot has the errors in a seperate object BindingResult. If you use Thymeleaf, this is smoothly integrated and you just write: <p th:if="${#fields.hasErrors('comment')}">Invalid Comment</p>
Grails Framework (Spring Framework more like Rails) integrates errors directly into the domain model, so if you have a domain class Person, it was extended with person.errors property.
More often than not, forms are the database model. They very frequently evolve together. The entire data transfer object to model copy back and forth is unnecessary most of the time
If the form is basically raw CRUD then it works out well, and being able to get up and running quickly and replace it with something more sophisticated later when you actually need that is a good thing.
It does require the discipline to actually _do_ the 'replace it' part when you reach that point and the results of failing to do that are ... not pleasant ... but that doesn't mean it's _always_ the wrong choice, especially when getting started.
It goes further than that. The form gets passed the model and it's name and based on that also drivers the URL and http action to take.
IMO this is good coupling since it's very loose, trivially changed and eliminated boilerplate code that's just noise. Of course, as always, it depends on a number of circumstances what trade-off is best for you, your team, the specific problem, etc
It depends a lot on the application. I have a little Django app that I haven't updated in years and is used by one person—it's basically just a nice frontend for a database. For that use case, being able to just directly plug forms into database models is super convenient!