Rubocop and Rails: Getting started

Feeling good about your Rails project? Think your Ruby code is ready for a peer review? I have a cure for those warm and fuzzy feelings – run it through a lint program or two.

Enter rubocop. (A serious mood killer.) I also added haml-lint to the party. (Ouch!)

Actually, true confession, I’ve always loved style guides and lint tools. They appeal to the tidiness freak in me. Plus anyone who’s been coding professionally for even a short time has picked up someone else’s code and wished like crazy the previous coder had followed a style guide (of any kind!) And before scoffing at how pedantic a strong lint tool can be, think of it as an environmental issue – leaving the planet of code cleaner, healthier and a better place than you found it.

The following are the steps I took to clean-up a small Rails4/Ruby2 project along with some tips.

Kudos, btw, to rubocop for having a really useful manual. It’s worth a read before going any further. If you get stuck, it’s the first place to check.

 

Clean start

Make sure there aren’t any outstanding, uncommitted changes in the code you’re working with. You’ll need to be able to revert to your starting files if something goes wrong. (And it probably will given the tedious, mind-numbing corrections you’re about to make. Typos happen.)

Reality check: If your Rails project isn’t already parked in git or SVN or some kind of source code control scheme, go do that first. Lint is not your biggest problem.

 

Install gems

Install the rubocop gem. I’m using HAML so I also installed the haml-lint gem.

Or, like I did, add them to your Gemfile if bundler is better for your workflow.

At this point, if you just can’t help yourself, run rubocop -RD from the root of your Rails project. Chances are you’re watching a steady stream of violation messages. Don’t despair, it’s (probably) not as bad as it looks. (Plus think of how virtuous you’re going to feel when this is all cleaned up.)

 

Create a .rubocop.yml config file
  • Add an empty .rubocop.yml file to the root of your Rails project source.
  • Run rubocop --auto-gen-config.
    The .rubocop_todo.yml file generated contains a list of the failed lint checks with a count and the check disabled. This allows you to enable each lint check individually.
  • Add the line

    to the top of your .rubocop.yml file.
  • Add the inclusions and exclusions recommended by rubocop for a Rails project.
    This is the .rubocop.yml that I started with:

 

Run, fix, test and repeat. And repeat. And repeat. And repeat …

There’s no right or wrong way to do this. It’s just a matter of plowing through the work, repeating the cycle of

  • enabling a lint check in .rubocop_todo.yml,
  • running rubocop,
  • fixing, adjusting or disabling the violations that appear,
  • and periodically running your tests to make sure no errors were introduced.

Then repeat this cycle with haml-lint.

When you’re done, remove the rubocop_todo.yml line from the top of .rubocop.yml.

 

Tips
  • Start working with rubocop without the -R option. Once that’s clean, turn on the Rails specific checks. The Rails violations are probably going to require a little more thought and investigation.
  • The -D option is very useful since it connects the violation message to the lint check that failed. (Not sure why it’s not on by default?)
  • Update (6/29/16): create a .rubocop file at the root of your Rails app for default command line options such as -RD
  • Try to avoid creating multiple .rubocop.yml files. Ask yourself first, is this really necessary or am I being lazy?
  • One set of files that does need a custom .rubocop.yml file is Rspec. I ended up with the following at the root of the Rspec files:

    The violations generated by some of Rspec’s standard formatting are okay to ignore for now and could obscure any real issues. Don’t forget to inherit the main .rubocop.yml file.
  • There are going to be rules that you decide you just don’t care about, flat out disagree with or will take care of later. For those, transfer the lint check from the rubocop_todo.yml file to the main .rubocop.yml file with a comment on why it’s there. (Your future self with thank you.)
  • I didn’t use the --auto-correct option since I wanted to understand exactly what was being modified. But that doesn’t mean that grep and sed can’t be your friend. For example:

    or

    They are your friend until they’re not! Be sure to limit the name and/or location of any mass search and replace. For example, doing a too broad search/replace for spaces can harm your git repository if you’re not careful.
  • If you get stumped on what to do about a failing lint check, look for comments and options in the rubocop config files: default.yml, disabled.yml and enabled.yml.
  • When I found individual lines or methods that needed more work, I added

    to the source. Then found them later using a simple
  • Thankfully haml-lint uses the rubocop config files.
  •  

    Update (6/29/16): rubocop-rspec

    The rubocop-rspec gem also looks useful and picked up a couple inconsistencies I hadn’t noticed.

    • Add
      to the development group in your Gemfile.
    • Run rubocop --require rubocop-rspec
    • After working through the issues, probably a good idea to require rubocop-rspec in your .rubocop.yml file so it’s part of each run.

     

    Integrate as a regular practice

    The final step is to add all this to your regular work process. (I added reek and rails_best_practices as well to what they would pick up.)

    Save the above as lib/tasks/testcode.rake and then run rake testcode.

     

    Conclusion

    On the first pass of a small Rails4/Ruby2 project with very little legacy, I ended up with 5 .rubocop.yml files (gist of config files) Some of the settings like MethodLength I’ll be revisiting in the future but it’s okay for now.

    I also installed and tried out the ruby-lint gem but was unable to get it to generate useful output for a Rails project. Hopefully in the future this will work since it sounds like a good compliment to rubocop. (If you got it to work with Rails, please comment below. I’d love to hear how.)

    References
    Ruby Style Guide
    rubocop gem
    haml-lint gem
    ruby-lint
    rails_best_practices
    reek

    Update Feb 7, 2017: New blog post Rubocop and Rails: Keeping Up-to-date. Rubocop has a rapid release cycle so this is not a one-time project!