ActiveRecordの #or を使うときは、こう考えると良さそう
Rails5で追加された #or
について。
(どうでもいいけど、このメソッド、ググラビリティ低すぎぃ)
社内で話してたら、Twitterで会話されてた。
@kamipo https://t.co/UQaAbt7M7T これrails 5.1でも .or(where(...)) が括弧で囲まれないんだけどバグちゃうの?
— FUJI Goro (@__gfx__) 2017年7月3日
つまりこう考えれば良いということか。
↓
「whereを AND
だと思ったうえで、メソッドのチェーン順に従う。」
と思えば良いのか。
Model .where(A) .where(B).or(C)
は改行のせいでgroupingが存在している気になるけど、字句解析結果は結局のところこう↓
Model.where(A).where(B).or(C)
これを、チェーン順に解釈すれば確かに
A and B or C
になる。一方、
Model.where(B).or(C).where(A)
なら、チェーン順とはすなわち「or Cが先」を意味することになる。これはSQLの演算子結合順と異なるため、ARが勝手に
(B or C) and A
にしてくれる、と。
「順序で結果が変わるのは後でバグを誘発し易いから避けたい」と思う場合は、「明示的に括弧を書く」と同じことをARのDSL上でやればよい。つまり、こう。
Model .where(A) .where(Model.where(B).or(C))
余談
これ、「直感とのズレ」が起こる本質的なポイントは、そもそもSQLにあるんじゃねーか?
ANDの連結を「項」と考えると↑の議論は意味がわかるけど、SQLにおいては「項」にあまり意味がないことが多い。むしろ、ORの連結の方に「filter単位」という意味があり、filter単位をANDするという考え方をすることが多いはず。「項」と「filter単位」のどちらを基準と考えるかで、どちらが直感的かの捉え方も変わるなぁ。