The fundamental truth of software development is that code is subject to change, all the time. As long as an app is in business, there are bugs to be fixed, new features to be implemented, and extensions to existing capabilities to be added. Therefore, the one practical aspect that reveals the health of a codebase is how easy it is to change it.
All meaningful efforts in planning and designing software has the ultimate goal of allowing changes to be easy and quick. The qualities observed in good software, such as loose coupling, small components, sane hierarchies, predictable and honoured contracts, are all there because they allow code to be easily understood and changed fast. Code that can accommodate changes easily and fast is the foundation of successful product development; code that is hard to change slows development teams down until their products are unmaintainable and become obsolete, and finally gets them out of business.
The Ruby on Rails Advantage
Ruby on Rails gained so much popularity because it allows new teams to get up and running quickly. This speed comes first of all from Ruby itself: a dynamic, loosely typed language focused on simplicity and productivity. Ruby empowers developers to save a lot of syntax in order to get things done faster, cutting out cumbersome checks and syntax overload by trusting that the programmer is making right decisions - which at least in the beginning of an agile development for a small app maintained by a small team, is a completely acceptable compromise.
Rails itself is a step further, now specific to web app development: out of the box it gives you all you need to have a fully fledged web app up and running, including HTTP server, relational database, and view templates. For standard CRUD operations in static web pages, developers hardly need to write any code at all: everything is generated by Rails via the command line. Ruby on Rails pioneered the market of web frameworks that can get an app up and running in seconds, and it would be hardly justifiable to go with a different tooling if the goal is to go from zero to done as quickly as possible.
When pure Rails is just not enough
By design Rails does not give everything that is needed to create a robust app that is supposed to handle incoming changes in the long term. An app generated by Rails contains the bare minimum needed to be in production fast: basic HTTP capabilities, basic HTML templating, and database persistence. Rails does not differentiate between a pet project of a 10 minute blog development or an entire multi-merchant commerce platform. Adapting and extending what Rails gives by default to the business needs is the responsibility of development teams. Just like Ruby trusts developers not to pass an orange when an argument is supposed to be a banana, as well as handling nil return values, Rails trusts developers to keep their codebases sane.
Developers, on the other hand, cannot always afford to do this preemptive planning and design exercise. Less experienced developers simply trust that the Rails way is the unquestionable status quo, generating unmaintainable code; more senior developers, even when they know they should do better, delay such important design decisions to a “future refactor once the project is over”, accumulating technical debt that is never paid.
These situations are so common in the Rails world that it is almost the norm. If there is a Rails app minimally organized, it stands out immediately like a miracle. These apps are not miracles; they simply adopt preemptively good design practices and patterns that allow a Rails codebase to grow and change in a sane manner, and the team behind them are committed to the long term success of their products.