
Ruby on Rails:
A critical look at seven 'bad practices'

Ruby on Rails is a mature Glossary · In brieffull-stackFull-stack describes software development that covers both the frontend and backend of an application. It can refer to a developer, team or technical tool.Read more web Glossary · In briefframeworkA framework is a coherent foundation for software development, providing reusable code, a defined structure and conventions for building an application.Read more with a pleasant syntax that lets you build something very quickly. My name is Remco, and hoping I never run into them again, at least within 10KB, I gave a workshop on bad practices in the Rails ecosystem. Because just because Ruby allows it does not mean you should approach it that way.
Just because Ruby allows it does not mean you should approach it that way.
What is Ruby on Rails?
Ruby on Rails is a full-stack web application framework built on the MVC architecture principle. It is known for Convention over configuration, DRY (Don't Repeat Yourself) and the speed with which you can get something into production. RoR delivers a cartload of built-in solutions for things like:
- Routing
- View rendering
- Form processing
- Database schema management
- Background jobs
- Email handling
The framework is deliberately 'opinionated' in design: it makes clear choices about how you are supposed to approach things.
Experiences from developers
Within 10KB I asked a few colleagues for their unvarnished opinion on the strengths and weaknesses of Ruby on Rails. Those conversations produced this:
Nice about RoRails
- Ruby gives a lot of freedom
- Elegant syntax (like 'unless')
- No compiler
- Developer happiness ranks high
- 'Automagic' and predictable
- Good scalability

Annoying about RoRails
- Magic autoloading
- Automatic chaining (method, callback, dependent)
- Metaprogramming (Define_method)
- Poor IDE integration
- Modest concurrency compared with Node.js
- Long test files
- No static types
- A fervent community
About that IDE integration
There are a few ways to integrate your development environment better. A paid package is RubyMine. For VS Code/Cursor there are several alternatives:
- https://achris.me/posts/setup-ruby-vscode/ (good blog with extensions and settings)
- Ruby LSP
- Bust a Gem
- Rails Schema
- Rails Open Partials
I have not tested them all myself, so feel free to try them out and let me know if you know other options.
On to the "bad practices"
Just because so much is possible does not mean it is smart. Such judgements are extremely subjective. What one person sees as 'a handy tool' makes another cry with misery. The following seven things at least make me cry:
1. Monkey Patching
When you modify or override third party code you quickly get unpredictable behaviour and code that is barely maintainable. It may be allowed, but more often it pays to respect existing functionality and extend it through the proper channels.
2. Metaprogramming
With define_method and dynamic class creation you sacrifice readability, and that is a shame. Especially Class.new(self) and eval constructions quickly result in spaghetti that nobody can make sense of. Debugging is then out of the question.
3. Concern Mazes
Using concerns too freely creates tangled Glossary · In briefdependencyA dependency is a software component or system that other software needs in order to build or run, such as a library, framework or external service.Read more and code paths you can no longer follow. Be sparing with concerns and keep the structure of your application clear above all.
4. Validation Overrides
Bypassing model validations with methods like .update_all() or .save(validate: false) invites inconsistent data. It is crucial to honour your validations, they protect your data after all. Only in very exceptional situations do you leave them aside.
5. Custom Database Types
Defining your own Glossary · In briefdatabaseA database is a structured collection of data that software can store, retrieve and modify. A database management system controls access to that data.Read more types sounds handy, but that way you quietly create a heavy dependency on one specific database implementation. You do not notice until the moment you want to migrate to another database. Trust me...
6. Callback Hell
Rails is full of callbacks: before_validation, after_save, around_destroy and I could go on. Before you know it you have spaghetti of hidden code paths that nobody can make sense of. Use callbacks sparingly and make sure the flow of your application stays crystal clear.
With great power comes great responsibility.
7. &block Passing
Passing code blocks as an argument is a powerful trick, and that makes the temptation to sprinkle them around large. But the logic rarely becomes more readable and testing quickly becomes a headache. Save that technique for the moments when it really adds something.
Conclusion
Ruby on Rails is a flexible framework for web development, that much is beyond dispute. But to quote Voltaire: 'with great power comes great responsibility'. If you recognise the built-in pitfalls and the bad practices of the framework and then neatly avoid them, you write code that lasts longer and that your colleague will thank you for.
In practice
Want to get hands-on with these ideas yourself? Here you will find a special repo full of exercises: workshop-rails-10kb. Have fun!
READ MORE
Related articles
Ewout

Work together?
Have a software question or a project in mind? Get in touch with Ewout to discuss what you need and how we can help.


