This is the ultimate guide to Ruby on Rails project RuboCop setup in 2020.
Table of contents
Let's get started.
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.
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 fasterer gem, based on the open-sourced Github repository called Fast Ruby - the biggest collection of Ruby benchmarks.
Let us now take a look into other, framework-specific RuboCop extensions.
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 GitlabCI or CircleCI.
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.
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 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:
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:
By default, it uses the predefined RuboCop configuration with no other extensions installed, as it 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:
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 the
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:
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:
That way the Ruby on Rails codebase quality is going to improve vastly over time, eventually allowing developers to remove the TODO list completely.
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:
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:
It's quite a copypaste task to keep it all up to date.
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.
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.
CTRL + Ffor the "Enabled: false" phrase.
At the time of writing this guide, there are 35 occurrences of the searched phrase, two of which are 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 class body.
Layout/FirstArrayElementLineBreak: Checks for a line break before the first element in a multi-line array.
Layout/FirstHashElementLineBreak: Checks for a line break before the first element in a multi-line hash.
Layout/FirstMethodArgumentLineBreak: Checks for a line break before the first argument in a multi-line method call.
Layout/FirstMethodParameterLineBreak: Checks for a line break before the first parameter in a multi-line method parameter definition.
Layout/HeredocArgumentClosingParenthesis: Checks for the placement of the closing parenthesis in a method call that passes a HEREDOC string as an argument.
Layout/MultilineArrayLineBreaks: Checks that each item in a multi-line array literal starts on a separate line.
Layout/MultilineAssignmentLayout: Check for a newline after the assignment operator in multi-line assignments.
Layout/MultilineHashKeyLineBreaks: Checks that each item in a multi-line hash literal starts on a separate line.
Layout/MultilineMethodArgumentLineBreaks: Checks that each argument in a multi-line method call starts on a separate line.
Lint/HeredocMethodCallPosition: Checks for the ordering of a method call where the receiver of the call is a HEREDOC.
Lint/NumberConversion: Checks unsafe usage of number conversion methods.
Migration/DepartmentName: Check that cop names in
rubocop:disable(etc) comments are given with department name.
Style/AutoResourceCleanup: Suggests the usage of an auto resource cleanup version of a method (if available).
Style/CollectionMethods: Preferred collection methods:
Style/ConstantVisibility: Check that class and module constants have visibility declarations.
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 public methods.
failwith an explicit exception class and message, rather than just a message.
Style/InlineComment: Avoid trailing inline comments.
Style/IpAddresses: Don't include literal IP addresses in code.
Style/MethodCallWithArgsParentheses: Use parentheses for method calls with arguments.
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 arguments.
sendmay overlap with existing methods.
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
ClassStructure cop 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 order:
Next to those, there are multiple other
Style cops, that put together remind me of some very wise words that I've read a long time ago.
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.