【Rails】Rubocopは設定を誤ると地獄を見るぞ


Rubocopって何?

Rubocop(ルボコップ)とは、Rubyのコードレビューツールの一種です。

コードレビューツールとは、「インデントが揃っていない」 「無駄な改行・スペースがある」などの指摘を、RubyStyleGuideに基づいて、構文チェックを行います。

Rubocopは、1行あたりの文字数制限や、文字列はすべてシングルクォーテーションで囲まなければならない、などのルールをデフォルトで定めています。
文法的にはエラーにはならないものの、コードの可読性を下げるという理由で設定されています。

※構文チェックは下記コマンドをターミナルで実行します。
設定方法は後述参照

bundle exec rubocop

※下記は1行が長すぎると怒られているエラー例
1行が198文字を超えてるから、160文字以下にしなさいと怒られています。
はい、すみません((((;゚Д゚)))))))

Offenses:

bin/bundle:104:161: C: Layout/LineLength: Line is too long. [198/160]
    warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"

[前半]Rubocopのコマンドは安易に使うべからず

構文チェックに使うbundle exec rubocopに似たコマンドの使用に注意しましょう。
私は下記のコマンドで地獄をみました。

※要注意コマンド
bundle exec rubocop -a

bundle exec rubocop -A

Rubocopが親切心で自動修正をしてくれるコマンドですが、使用した事で厄介な事が起きました。

何も考えずに安易に使用すると、修正しなくて良いファイルまで修正されてしまいます。
最終的に手動で修正する手間が増えて、ファイルも重くなるという地獄を運んできます。

地獄その1: 修正しなくていいファイルも修正された
地獄その2: rubocopが自動修正したものと自分の手で修正したものが混ざってしまった

コマンドの効果の一つとして、文字列を囲うシングルクォーテーションを、全てのファイルでダブルクォーテーションにRubocopの親切心で自動修正されます。全てのファイルで、です!!

この時点でRubyの規約違反になりますし、英語の文脈がおかしくなるもあります。
必要のないファイルが変換される無意味さに加え、コードの保守性を損ねるだけです。
コミットをプッシュした後だと更に泣けてきます😭

そこでコミットした内容をなかった事にするコマンドを下記に記載しておきます。
でも多用したくないコマンドです😓

[地獄対策①]コミット前の状態に戻す方法

コミットしたファイルはコミット前に戻す事は、下記コマンドでコミット前に戻せますが、手動なので修正漏れが発生する恐れがあります。

①git logでコミット番号を確認
②git checkout {コミット番号} {コミット前に戻したいファイル名}

その為、自動修正が必要ないファイルは、後述する.rubocop.ymlファイルのExclude: の下に追加しておく事を強く推奨します。除外さえしておけば、自動修正コマンドが動いてもその影響から免れます。

[地獄対策②]vscodeを使ったコードの一括修正方法

もし手動でコードを修正する場合ですが、便利な手段を知ったので記載します。

同じファイル内で同一の記述を個別、または全て文字列を任意のものに変換できます。
個別修正と一括修正のどちらも可能ですが、修正の必要不要に関してはコードをチェックした上で行ってください。英語の文法がおかしくなる恐れがあります。



以上でRubocopの構築に際して沼った部分と対策は終わりです。
長くなりましたが、ここからがRubocopの使用準備です。

[後半]Rubocopの使用準備 

まずは必要なGemとファイルを作成します。

  • Gemfileの記述
  • rubocop.ymlファイルの作成

現役エンジニアの方から伺った話ですが、実際の開発現場でも先輩エンジニアがコードレビューツールの使用準備を終えており、使用準備に関わらない事は普通にあるそうです。

  • Rubocopを構築した環境
    • Ruby2.7
    • Docker
    • Ruby on Rails6
    • Vscode

RubyのLintであるonkcop/pre-commitを入れたら、個人開発が幸せになった話
Rubocopの使用準備にあたり、上記の記事を大いに参照しています。
ありがとうございました😃

今回は、Gemfile内の:development doの部分に以下を記述します。

gem 'onkcop', require: false
gem 'rubocop-rails'

上記のonkcopは、Rubocopの拡張版でオニクコップと読むそうです。
onkcopの公式リポジトリはこちら

続いて下記コマンドをターミナルで順に実行します

①bundle install
②bundle exec onkcop init

そうすると、.rubocop.ymlというファイルが作成されるので、次のように書き換えます。

rubocop.yml
require:
  - rubocop-rails

inherit_from:
  - "config/rubocop/rubocop.yml"

inherit_gem:
  onkcop:
    - "config/rails.yml"
    - "config/rspec.yml"

AllCops:
  TargetRubyVersion: 2.7.1 ←※バージョンはruby -vで確認して合わせましょう。
  TargetRailsVersion: 6.0.3.4 ←※バージョンはrails -vで確認して合わせましょう。
  Exclude: ←※とても重要な部分
    - "vendor/**/*" # rubocop config/default.yml
    - "db/schema*.rb"
    - "node_modules/**/*"
    - "db/migrate/**/*" ←※構文チェックが不要ファイルがあれば、この下に追記していく。

使用準備はこれで終わりです。
そしたらコマンドを実行しましょう。

rubocopによる構文チェック(パトロール)の実行

あとはターミナルでbundle exec rubocopコマンドを打てば、Rubocopが無駄なコードを炙り出してくれるので適宜修正していきましょう。

bundle exec rubocop

コマンドを叩くと、下記のような大量出力が出てきますが、これがコード記述の規約違反です。これらがrubocopのパトロールに引っかかった構文エラーなので、適宜修正していきます。

最終的に、ターミナルでbundle exec rubocopコマンドを打ってコードに問題がなくなれば、下記のような表示に落ち着きます。

Inspecting 7 files
.......

7 files inspected, no offenses detected

また別途、重要になるのは.rubocop.ymlファイル内のExclude: の部分です。

bundle exec rubocopで構文エラーを炙り出すのですが、そもそもパトロールの必要がない部分もあります。Excludeは「除外」の意味なので、Excludeの下にパトロールの必要がないファイル名を記載する事で、Rubocopのパトロール時間が短縮できます。

パトロールの必要がない判断基準としては、Railsで自動生成されたファイルです。
加えて、人間が手を加えないファイルです。
手を加えない自動精製ファイルはパトロールさせるだけ時間の無駄です。

具体的には下記のようなRailsで自動作成されるファイルたちの事です。
任意でExclude:の下に追加していきましょう。

rubocop.yml

※ここより上のコードは省略

AllCops:
  TargetRubyVersion: 2.7.1 
  TargetRailsVersion: 6.0.3.4 
  Exclude: 
    - "vendor/**/*" # rubocop config/default.yml
    - "db/schema*.rb"
    - "node_modules/**/*"
    - "db/migrate/**/*" 
    - "app/channels/**/*"
    - "config/**/*"
    - "config.ru"
    - "bin/**/*"
    - "public/**/*"
    - "tmp/**/*"
    - "log/**/*"

上記のようにExclude: の下に追加したディレクトリや配下ファイルは、Rubocopによるパトロール対象外となります。以上でRubocopの注意点や使い方は終わりです。

使ったことのないコマンドには本当に気をつけよう((((;゚Д゚)))))))