Rubocop and Rails: Keeping Up-to-date

Updating your Rails application and workflow with the latest Rubocop release

Integrating rubocop into your Rails application work flow is just the beginning. This is not a “set-it-and-forget-it” relationship. Ruby is continually evolving and so is the style guide. Thankfully there is an active community committed to keeping rubocop up-to-the-minute.

Because rubocop updates are happening so rapidly, the README suggests locking the rubocop version in your Gemfile to avoid breaking change surprises. Not a bad idea since they’re not kidding about rapid changes but keep in mind that you miss out on all the benefits of a linter if you let it get too out-of-date. (Right?)

Not all of the following step are strictly necessary but the goal here is a full, explore all the corners, clear out the cobwebs update.

Btw, if you haven’t previously installed added rubocop to your Rails application I suggest checking out a previous blog post about getting started with rubocop first.

Okay, let’s get started:

Create a solid starting point

  • Commit or discard any uncommitted changes. Use a “WIP” commit if you need to. git diff is going to be your new best friend.
    Although working in a new branch is also a good idea, you are potentially about to modify a whole lot of files. Merging the branch back in could be painful if you’re uncertain of your starting point.
  • If you are still using a .rubocop_todo.yml file, now is the time to finish handling what’s outstanding. The .rubocop_todo.yml file is going to be overwritten later on.
  • If it’s not already under source control, make a backup copy of .rubocop.yml for safe keeping.

Update your rubocop version

  • Update the rubocop gem. If necessary, don’t forget to unlock the version in your Gemfile.
    or
  • Check rubocop will be using the right target Ruby version. To fix this, see Rubocop’s doc on how to set the target Ruby version.

Start setting up the .rubocop.yml file

Sometimes when new cops are added, they are disabled by default. These need to be included in the update to look for anything interesting and/or useful.

At some point in the future (and I’ll update this section when/if it happens), we’ll be able to set the reverse of DisabledByDefault to automatically enable all cops by default. But in the meantime, it’s not that hard to do by hand.

  • At the bottom of the .rubocop.yml file, add lines of comments for an obvious visual demarcation between the existing configuration and what we’re about to add. (Sounds trivial but trust me it will help with all the cut and paste.)
  • Find config/disabled.yml in the github.com repository for rubocop. Copy the contents of the file into the bottom of the .rubocop.yml file below the demarcation line of comments.
  • (Hint: To grab a single file from a github.com repository, hit the Raw button, then copy and paste from the browser.)

  • Edit the section of text you just added:
    1. Delete the lines Rails: Enabled: false.
    2. Remove any cops that are duplicates. In other words, already listed above the demarcation line.
    3. Go through and flip the Enabled: false to Enabled: true.

Generate a TODO list to work against

  • Now that .rubocop.yml is set-up to catch any new but disabled cops and we have the latest rubocop version installed, it’s time to create a TODO configuration file .rubocop_todo.yml just like we did when doing the initial integration.
  • This is important. Once you have a .rubocop_todo.yml file, comment out the section you added to the bottom of the .rubocop.yml file. You want these cops to now be pulled in from the .rubocop_todo.yml file.
  • Add the line to the top of the .rubocop.yml file

Work through the TODO list

Now begins the process of working through each cop in .rubocop_todo.yml. Iterating through the updates. This should be a familiar process and hopefully much less painful that the initial rubocop integration (as long as you’ve been keeping up with the updates!) I wrote more about this process in a previous blog post.

Some Additional Thoughts

  • Seriously. No matter how tempting. Do not just blindly run the auto correct without understanding what you’re correcting. This can lead to unpleasant surprises. Plus part of this process is learning where your code is deviating from the ruby style guide and understanding why.
  • Review the CHANGELOG. Even a quick read could alert you to something related to the settings in your .rubocop.yml that you need to update.
  • In particular, this is a good time to review the cops that are disabled. Could be that a change was made that would now allow you to enabled it with some configuration.
  • Review for extra .rubocop.yml files in sub-directories that can be eliminated. For example, rather than having a .rubocop.yml file in the ./specs directory to turn off cops that don’t work for Rspec, exclude the ./specs directory in the main .rubocop.yml file.

  • Don’t forget to also review the cops disabled inline in the code.

    For example, if a cop is disabled at the top of the source file consider excluding the file specifically in .rubocop.yml instead of have a “magic comment” in the source file.
  • For the cops from config/disabled.yml, in the interest of not duplicating work during the next update, enable or disable them in your .rubocop.yml file now. For example, if you know that you’re never going to be adding a copyright message to every file, disable Style/Copyright so you know to ignore it next time.
  • If you really want to geek out, not just the CHANGELOG but the open issues and pull requests as well as the repository change histories make for interesting reading. (Just saying.)

A Final Thought

If rubocop is a valuable part of your workflow (and if you’re still reading at this point, how could it not be), consider making a donation or becoming a sponsor.