💬

RuboCop::Cop::Rails::PresenceというRubocupの指摘

2022/04/16に公開

Rubocupでリファクタリングをしていたところ、モデルのメソッドで次の指摘を受けました。

models/sample.rb
C: [Correctable] Rails/Presence: 
Use [別テーブルのidを格納した配列を弄る処理].presence || [] 
instead of [別テーブルのidを格納した配列を弄る処理].blank? ? [] : [別テーブルのidを格納した配列を弄る処理]
変数 = [別テーブルのidを格納した配列を弄る処理] ? [] : [別テーブルのidを格納した配列を弄る処理]

元の記述は配列を処理した結果、空配列であれば空配列を、そうでなければ処理した結果の配列を返すという単純なものですが、同じ記述を2回繰り返す点でDRY原則に沿った書き方ではありませんでした。

今回の指摘で簡潔に書けることがわかりましたが、これまで見かけない記述でしたのでまとめておきます。

短絡評価について

https://qiita.com/gyu-don/items/a0aed0f94b8b35c43290

||の場合は、
||の左側がtrueの場合、||の右側が何であってもtrueを返す
||の左側がfalseの場合、||の右側がtrueだとtrueを返し、falseだとfalseを返す
つまり、&&の左側がfalseの場合や、||の左側がtrueの場合は、右側の値を見る(評価する)必要はない。言語として、この場合は>右側の値を評価しない、という仕様にすれば、多少は無駄が省けるかもしれない。そのような仕様を「短絡評価」と呼ぶ。

今回の場合は、[別テーブルのidを格納した配列を弄る処理].presenceがtrueであれば、trueを返し、
そうでなければ、右側の値をbool値を返すということになります。

実際に返すのは次の記事に記載のある規則に従い、bool値ではなく処理の結果か空の配列になります。

https://qiita.com/Yametaro/items/17f9b2baa67440b8664a

sample.js
const name = user.name || "名無しさん";

ワイ「ああ、なんかワイも見たことあるわ」
ワイ「ユーザーの名前が存在すれば、その名前を代入するし」
ワイ「存在しなければ取り敢えず"名無しさん"を代入しとく、いうやつやな」
ワイ「if文とか使わずスッキリ書けるな」

今回はif文ではなく、三項演算子を使用しておりましたが、それでも簡潔にかけました。

presenseメソッドについて

Rubocupのページには次の記述があります。

https://www.rubydoc.info/gems/rubocop-rails/RuboCop/Cop/Rails/Presence

This cop checks code that can be written more easily using Object#presence defined by Active Support.

presenceメソッドを使えば、簡単に書ける場合をチェックしているとのことです。
presenceメソッドの説明をしていないので、他のページを見ましょう。

https://apidock.com/rails/Object/presence

Returns the receiver if it’s present otherwise returns nil.

存在していればその値を返し、そうでなければnilを返すとのことです。
記載されている例でも短絡評価が使用されています。

sample.rb
state   = params[:state]   if params[:state].present?
country = params[:country] if params[:country].present?
region  = state || country || 'US'
sample.rb
region = params[:state].presence || params[:country].presence || 'US'

次の記事にもあるように色々と簡潔な書き方ができるので積極的に使用したいですね。

https://techracho.bpsinc.jp/hachi8833/2021_02_26/62326

Discussion