Ruby on Rails project RuboCop setup with RSpec
Table of Contents:
- What is RuboCop and Ruby Style Guide?
- RuboCop Performance
- RuboCop Rails and Rails Style Guide
- RuboCop RSpec and RSpec Style Guide
- RuboCop MiniTest and MiniTest Style Guide
- RuboCop set up in a single Ruby on Rails project
- Sharing RuboCop configuration in multiple Ruby on Rails projects
- Advanced RuboCop configuration
This is the ultimate guide to Ruby on Rails project RuboCop setup in 2020.
Let's learn all about configuring RuboCop in Ruby on Rails project...
What is RuboCop and Ruby Style Guide?
RuboCop is the most popular Ruby static code analyzer and code formatter, code linter in short. Linting is the process of running a program that analyzes the code for programmatic and stylistic errors.
Out of the box, it enforces most of the guidelines outlined in the Ruby Style Guide maintained by the Ruby community. The guide groups its guidelines by related sections, which corresponds to RuboCop gems departments.
There are nine departments in the base RuboCop gem. Numbers might change in time and are given here only for the rough overview of what the gem offers.
- Layout - 87 cops
- Linting - 81 cops
- Metrics - 10 cops
- Migration - 1 cop
- Naming - 16 cops
- Security - 5 cops
- Style Cops - 170 cops
- Bundler - 4 cops
- Gemspec - 4 cops
In total, there is a little less than 400 rules applicable to anything written in Ruby, if we choose so.
But, it does not end here - let us take a quick look at accelerating the Ruby code by following extended RuboCop guidelines.
There's an extension wisely encapsulated in its own Ruby gem called RuboCop Performance. Its job is pointing out Ruby code optimization opportunities.
All 25 rules of the RuboCop Performance gem are grouped in the single RuboCop department, called Performance.
It is a relatively young project and some of the cops included were originally placed in the main RuboCop gem.
If your Ruby program is really performance-dependent, you might want to
additionally look at the
gem, based on the open-sourced
Github repository called Fast Ruby - the biggest base of Ruby
Let us now take a look into other, framework-specific RuboCop extensions.
RuboCop Rails and Rails Style Guide
When RuboCop is a code linter of your choice, RuboCop Rails extension is the must-have for your Ruby on Rails projects.
RuboCop Rails is a RuboCop extension focused on enforcing Ruby on Rails coding conventions and best practices, neatly described in the Ruby on Rails Style Guide.
The style guide itself is split into 16 sections, covering things such as Ruby on Rails configuration, dealing with time, Models, Controllers, Mailers and more.
Whenever in doubt on how to approach Ruby on Rails related problem, try browsing the relevant style guide section, or go one step further and let your projects Continuous Integration point it out for you, by configuring RuboCop gem with all its extension on either Gitlab CI or CircleCI.
RuboCop RSpec and RSpec Style Guide
If RSpec is your weapon of choice unit-testing-wise, setting up the RuboCop RSpec extension will help you a lot.
RuboCop RSpec is a RuboCop extension that provides RSpec, RSpec for Rails, FactoryBot and Capybara analysis for Ruby projects, which in total gives us another 76 rules to follow, for the sake of neat codebase.
All of the RuboCop RSpec cops - and then some - are extensively described in the RSpec Ruby Style Guide, providing examples of the code that follows the guideline paired with the one that does not.
It is my personal favorite style guide of all provided by the RubCop HeadQuarters, and I rely on it a lot during Code Reviews - my Github account saved replies are linking to it heavily.
Next to the gem itself, the guide gives an extremely useful overview of how to write unit tests of Ruby on Rails related parts, such as the MVC Models, Views, Controllers and also Mailers.
Unfortunately, some of the Rails related rules are not possible to enforce via the gem itself, hence the Github saved replies linking to the relevant guide sections.
It is still a great tool whenever you use RSpec in your Ruby and Ruby on Rails projects.
RuboCop MiniTest and MiniTest Style Guide
If you use MiniTest MiniTes, the second most popular choice for testing the Ruby written programs, there's a RuboCop extension dedicated to it, called RuboCop MiniTest.
It enforces best practices outlined in the MiniTest Style Guide, yet another great read provided by RuboCop HeadQuarters.
It's a relatively young project comparing to the more popular RSpec choice. It describes a total of 15 rules for writing unit tests using the MiniTest framework.
RuboCop set up in a single Ruby on Rails project
Now that we went through most of the RuboCop extensions - there are two more, for Rake and Markdown - let us take a look at how to hook it all up in the Ruby on Rails application.
RuboCop and its extension configuration files are written in YAML. They are all placed in the same config directory, in each of the repositories respectively, assisted with a great RubyDoc documentations, which altogether makes it very easy to find and understand every rule.
When working on the Ruby on Rails project that uses either RSpec or MiniTest, we are going to install 4 RuboCop gems:
- RuboCop Performance
- RuboCop Rails
- RuboCop RSpec or RuboCop MiniTest
Go ahead and edit your Gemfile, adding the following to the development and test group.
group :development, :test do gem 'rubocop' gem 'rubocop-performance' gem 'rubocop-rails' gem 'rubocop-rspec' # or gem 'rubocop-minitest' end
Next in your CLI, navigate to the directory path of your Ruby on Rails project
and run the
bundle install command in order to update your Gemfile.lock.
Now that all the gems are installed, let us prepare our custom RuboCop configuration file, called .rubocop.yml.
It is responsible for two things: - Importing installed extensions
- Defining which cops we do and do not want to enforce By default, it uses is designed to work with any Ruby language codebase.
In order to include the installed extensions, create the following RuboCop configuration file.
require: - rubocop-performance - rubocop-rails - rubocop-rspec # or rubocop-minitest
Next, we are going to follow the example configuration for Ruby on Rails project presented in the RuboCop documentation
- but in order to use the aforementioned extensions, we are going to skip some of it.
Add the following to your configuration file.
AllCops: Exclude: - 'db/**/*' - 'script/**/*' - 'bin/**/*'
It tells RuboCop to exclude given directories while analyzing the codebase - the readability does not matter there too much and is not worth bothering for the pleasing Ruby on Rails development.
Next, let us cut some additional slack while working with RuboCop. Those are the sane RuboCop rules to use with Ruby on Rails project.
Below the previous configuration, add the following.
Metrics/LineLength: Max: 100 Metrics/BlockLength: Exclude: - config/**/* - spec/**/* Lint/AmbiguousBlockAssociation: Exclude: - spec/**/* Style/Documentation: Enabled: false
Most of those are pretty self-descriptive, but let's go through them quickly:
- Line length cop - that's the one you might want to change to your liking -
- Block length cop is told to ignore the config and spec directories, as our contributors to write fewer tests, right?
- Ambiguous block association is turned off for the tests directory, as bbatsov,
- Documentation cop is turned off, as there are better ways to document the
It is important to remember that nothing here is written in stone - if you ever feel like you waste more time than its worth fixing some "stupid RuboCop rules", you can always disable them in this file.
At this point, assuming that you've recently created your brand new Ruby on Rails project the RuboCop analysis will give you some headache, as Ruby on Rails does not follow its default guidelines.
But worry not - most of it can be easily fixed using the RuboCop command with
Let's not be naive, everything can crash, no matter if its name contains "safe" - create a backup of your recent changes to git first.
Then, navigate to your project directory and run the following.
bundle exec rubocop --safe-auto-correct
It will fix all RuboCop violations that are marked as auto-fixable in the default configuration file. Browse the changes and if it seems ok, add it to git.
There's also a big chance that you work on some much older Ruby on Rails codebase, and the quick-fix presented above might not be that effective, nor the best idea - some stuff might actually break.
Thankfully to the awesome RuboCop maintainers, there's a solution for legacy
code implementations, the
--auto-gen-config command-line flag.
In the root directory of your legacy Ruby on Rails project after installing all the gems and creating the configuration file, run the following.
bundle exec rubocop --auto-gen-config
It does two things:
- Analyzes the codebase for RuboCop violations, writing the exclusions into the .rubocop_todo.yml file,
- Updates the .rubocop.yml file with an import of the exclusions.
Now, if you run the bare bundle exec rubocop command again, it will show 0 offenses.
This is a great way for improving legacy Ruby on Rails applications code: just tell your team, that whenever anybody works on it, they should: - Look it up and comment-out a path to it in the TODO file,
- Fix what's possible,
- Delete the commented-out paths exclusions for good.
That way the Ruby on allowing developers to remove the TODO list completely.
Sharing RuboCop configuration in multiple Ruby on Rails projects
It is easy to set the RuboCop up for a single Ruby on Rails project, although, following the current microservices trend, that's hardly enough. There's a big chance that wherever you work at, your team either:
- creates multiple Ruby on Rails projects monthly (like Software Houses do),
- maintains multiple Ruby on Rails projects
RuboCop evolves, all its extensions do too, and developers' preferences change. Maintenance of all those moving parts along with keeping sane is not a trivial task. Imagine that company you work for has 15 microservices, all written in Ruby on Rails, and consider one of the following:
- Your team decides that they don't like Department/Cop anymore
- RuboCop releases a newer version
- RuboCop Rails releases a newer version
- RuboCop RSpec releases a newer version
- RuboCop Performance releases a newer version It's quite a copypaste task to
Percy, the Continuous Delivery SaaS, and Google APIs Google propose (and use themselves) a solution to that - creating your own gem with all the required extensions installed, a single source of the RuboCop configuration.
With your own gem, the "only" thing you need to do is updating it (and either backward-fixing or ignoring the "new" violations after the update) in every single project. There's automatically less room for error, as the single configuration per project would require you to update the core, every single extension and on top of that, the configuration file.
There's another option available, although I'm not a big fan of it, as in my opinion it is not controlled enough and might actually do some damage - with RuboCop, you might include the configuration from an URL address, so theoretically you would not need to manually update it in every single project.
What I don't like about it: if you lint the code in your Continuous Integration suite, it might suddenly cause your jobs to stop passing if new rules won't be backward compatible with the old code - and as a result, stop the development just to fix them.
Summing up, if your team maintains and/or creates a lot of Ruby on Rails applications, consider encapsulating your RuboCop configuration in the separated, shared gem.
Advanced RuboCop configuration
For all the standards nazis like myself, I'm going to mention yet another detail that I've recently discovered about RuboCop: it does not enable all its options by default.
See it for yourself.
- Browse the config/default file in the core RuboCop gem repository,
CTRL + Ffor the "Enabled: false" phrase.
At the time of writing some explanatory comments.
It seems that there are 33 additional rules that one can potentially follow, improving the Ruby on Rails codebase even further!
Bundler/GemComment: Add a comment describing each gem.
Layout/ClassStructure: Enforces a configured order of definitions within a
Layout/FirstArrayElementLineBreak: Checks for a line break before the
Layout/FirstHashElementLineBreak: Checks for a line break before the first
Layout/FirstMethodArgumentLineBreak: Checks for a line break before the
Layout/FirstMethodParameterLineBreak: Checks for a line break before the
Layout/HeredocArgumentClosingParenthesis: Checks for the placement of the argument.
Layout/MultilineArrayLineBreaks: Checks that each item in a multi-line
Layout/MultilineAssignmentLayout: Check for a newline after the assignment
Layout/MultilineHashKeyLineBreaks: Checks that each item in a multi-line
Layout/MultilineMethodArgumentLineBreaks: Checks that each argument in a
Lint/HeredocMethodCallPosition: Checks for the ordering of a method call
Lint/NumberConversion: Checks unsafe usage of number conversion methods.
Migration/DepartmentName: Check that cop names in
Style/AutoResourceCleanup: Suggests the usage of an auto resource cleanup
Style/CollectionMethods: Preferred collection methods:
Style/ConstantVisibility: Check that class and module constants have
Style/Copyright: Include a copyright notice in each file before any code.
Style/DateTime: Use Time over DateTime.
Style/DocumentationMethod: Checks for missing documentation comments for
failwith an explicit
Style/InlineComment: Avoid trailing inline comments.
Style/IpAddresses: Don't include literal IP addresses in code.
Style/MethodCallWithArgsParentheses: Use parentheses for method calls with
Style/MethodCalledOnDoEndBlock: Avoid chaining a method call on a
caseexpressions to have an
Style/MultilineMethodSignature: Avoid multi-line method signatures.
Style/OptionHash: Don't use option hashes when you can use keyword
Style/SingleLineBlockParams: Enforces the names of some block params.
Style/StringHashKeys: Prefer symbols instead of strings as hash keys.
Let's check out one that I personally like the most, the
residing in the
As its description states,
Layout/ClassStructure enforces a configured order
of definitions within a class body. There are multiple things that can be
included in the Ruby class, and thanks to this cop we can make sure that all
the classes written in the codebase define them in the custom or default
- public, private and protected methods
Next to those, there are multiple other
that put together remind me of some very wise words that I've read a long time
Any codebase should look like it is written by a single person.
"Clean Code" by Robert Cecil Martin
That is the effect you might accomplish via the disabled by default RuboCop configuration.
RuboCop is a very powerful and the most popular code linting tool for the Ruby language.
Its configuration is not rocket science, so the amount of community knowledge on writing a clean, easily maintainable code comes with a very low price - all it takes is installing a few gems and writing a simple YAML file.
The only justification of not using it is knowing all those rules by heart - and I seriously doubt that there's a lot of people who do.
Using RuboCop when developing Ruby on Rails applications helps developers to avoid common mistakes, guards from the code formatting discrepancies and allows them to create a codebase that is well maintained and easy to understand.
Use RuboCop in your Ruby on Rails projects, period.