先日リリースした RuboCop Rails 2.6.0 でバグフィックスされた Rails/UniqBeforePluck
についての話。
この Cop は RuboCop Rails に細かな部署があるなら、スタイルではなくパフォーマンスに属するもの。RDBMS から結果を取得したあとに Ruby の uniq
で一意にするのではなく、DISTINCT
を使ったクエリを RDBMS に発行してあらかじめ一意になっている結果を得るもの。
デフォルトで以下のような検出を行う。
# bad Model.pluck(:foo).uniq # good Model.distinct.pluck(:foo)
なお、この Rails/UniqBeforePluck
cop はバグ修正された RuboCop Rails 2.6 以上でないと distinct
に置換すべきところ Rails 5.0 で非推奨にされた uniq
にオートコレクトしてしまう問題がある。
いまメンテナンスされている Rails 5.2, Rails 6.0 なんかでは NoMethodError: undefined method
uniq'` エラーになるので自動修正を使うときは RuboCop Rails を最新の 2.6.0 に更新してください。
なお Rails/UniqBeforePluck
は EnforcedStyle
のオプションを持っていて、デフォルトの EnforcedStyle: conservative
は偽陰性が起きえて、EnforcedStyle: aggressive
は偽陽性が起きうるという。常時はデフォルトの EnforcedStyle: conservative
のままとしている。パッチ会あたりでも聞いてみたいところ。
github.com
あとは悲しいかな、誤検知をもちうる Cop のため git grep 'pluck.*uniq'
なんかで置き換えが可能かどうかを見て判定というのが最初の導入として確実。まずは grep
で対応した後に EnforcedStyle: conservative
あたりで検出を行うというのが、まさに consavative なやり方になるだろう。型があれば誤検知なく EnforcedStyle: conservative
が使えそうで未来の処理系に期待される。
そして、Rails/UniqBeforePluck
cop は歴史的経緯ですでに名前が実体にあっていないので、RuboCop Rails 3.0 あたりでリネームされる予定です。
追記
同僚の kunitoo より例えば MySQL の collation によって、RDBMS によっては非互換が生まれる可能性があるかもという指摘があった。たしかに現状の実装だとオートコレクトの unsafe を検討できるかもしれない。