LoginSignup
8
6

More than 5 years have passed since last update.

Railsのクエリを書く上で、Squeelというgemを便利に使っていたのですが、別なものに乗り換えることにしました。

Squeelとは

ActiveRecordには各種のクエリメソッドがありますが、それだけでは不足する部分もあります。たとえば、「created_atが2週間前以前」というような条件をかけようとすると、以下のようになります。

# その1:文字列で書く
Model.where('created_at < ?', 2.weeks.ago)

# その2:Arelを使う
Model.where(Model.arel_table[:created_at].lt 2.weeks.ago)

ただ、これらの方法にはデメリットがあります。

  • 文字列で書くと、あとあとの再利用に差し支える場合もありえますし、なにより美しくありません。
  • Arelで書くとかなり長くなるし、記法はややこしいし、(Rails 5.0以前では)内部APIなので外から積極的に使っていいものか疑問もあります。

ということで、もっと綺麗に書けるgemとして「Squeel」というのがあります。これはArelをラップして、RubyのDSLとして書けるようにしたものです。

Model.where { created_at < 2.weeks.ago }

Squeelの問題点

Squeelはたしかに便利なのですが、大きな問題点として「ActiveRecordを大胆にモンキーパッチしている」ということがあります。その結果、ActiveRecordがバージョンアップするたびに、大規模な対応作業が必要となってしまう、という構造上の欠点があります。

そんな事情でRails 5対応が遅れていることもあって、「このまま継続して使うわけにも行かないな」と思えてきました。

Squeelなしでできること

ということで、ブロックを渡しているActiveRecordメソッドを調べてみたのですが、意外とSqueelなしで書けるものも多かったです。

  • 単なる等値比較
  • シンプルなサブクエリ
  • 範囲比較

また、ORクエリについてはRails 5から加わることを前提に、現状の4.2では.where.orで書けるようにしてSqueelから離れることができました。

BabySqueel

それでも書けないものも多いので(日付の大小比較など)、Squeelの後継としてBabySqueelに乗り換えようと考えています。こちらは、ブロックを取るwhere.where.has {}のように別メソッドとすることで、もともとのActiveRecordメソッドをモンキーパッチするコストを削減しています。

教訓

モンキーパッチしたものを維持するには、相応のコストがかかる

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6