LoginSignup
2

More than 5 years have passed since last update.

Squeelの書き方をRails5に対応させるメモ

Last updated at Posted at 2017-05-31

私のプロジェクトのRailsアプリケーションがついに4.2系から5.0系に進化するときがやってまいりました。

その際、 squeel が結構幅を利かせており、直すのに結構四苦八苦してしまいました。

なのでこちらではその忘備録とともに、同じくsqueelにsqueal(悲鳴)をあげる方々の助けに少しでもなればという事で書いていきます。

squeelについて

  • 公式
  • 実は私はsqueelは使った事がないので、よくわからないのですが、要は短く綺麗にActiveRecordへの指示を出せるGemだったようです。
  • さよならSqueelの記事にある通り、Rails5へのアップデートに伴い、ついにアップデートがされなくなってしまいました。

squeel修正対応表

  • では早速本題に向かいます。

今回メインで使うモデルについて

class Corporation < ActiveRecord::Base
  belongs_to :ceo
  has_many :users
end

class User < ActiveRecord::Base
  belongs_to :corporation

  attr_accessor %i(name)
end

order

複数のプロパティでソートをしている場合

  • squeelの公式には書いていなかったのですが、複数orderを指定する場合にこんな書き方ができたようです
User.joins(:corporation).order { [:name, :id] }
  • これに関してはすでに簡単にAcriveRecordで書けるようになっているのでありがたかったです。
User.joins(:corporation).order(:name, :id)

特に問題はなし

複数のプロパティ(親要素含む)でソートをしている場合

User.joins(:corporation).order { [:name, corporation.name] }
  • これはちょっと「ん?」となった。親要素ってどうやってソートするんだっけ?
  • これが正解
User.joins(:corporation).order(:name, Corporation.arel_table[:name])
  • さらっとarel_table使ってますが、Arelでクエリを書くのはやめた方が良い5つの理由(Rails 5.0以前の場合)の中盤に書かれてある通り、 5.1以降はarel_tableをガンガン使ってもいい方向性になるかもなので、使い方を覚えておいて損はないでしょう。
  • @jnchito さんからコメントいただきまして、arel_tableが今後ともまだプライベートAPIのままの可能性もあるということで、引き続き控えめにみておいた方がいいとのことでした。失礼いいたしました

  • ちなみに今回はbelongs_toしている対象が元のモデル名と同じだったからいいものの、

# user.rb
belongs_to :my_office, class_name: 'Corporation'

とかだった場合って迷いません?ですがこの場合はおとなしく

User.joins(:my_office).order(:name, Corporation.arel_table[:name])

が正解。

複数のプロパティ(親の親要素含む)でソートをしている場合

  • あまり考えたくないけどもこんなバージョンが来た場合
User.joins(corporation: :ceo).order { [:name, corporation.ceo.name] }

何重すんねんって思ったけども、この場合はこう

User.joins(corporation: :ceo).order(:name, Ceo.arel_table[:name])

いやはやarel_tableの仕組み覚えななぁ‥‥

DESC,ASCが入っている場合

User.order { [name, age.desc] }
  • 中かっこを使ってまとめてあげると見やすい
User.order(:name, { age: :desc })

joins(主にleft_outer_join)

  • 私のプロジェクトでは、squeelでjoinsを使っている場合は大概がLEFT OUTER JOINのためだった

一つのテーブルに対してLEFT OUTER JOINしている場合

User.joins { corporation.outer }
  • squeelのあった頃はLEFT OUTER JOINするのが面倒くさかったらしいです

  • これに対しては、Rails5ですでにメソッドが追加されているのでこう書きます

User.left_outer_joins(:corporation)
# もしくは
User.left_joins(:corporation)

どっちを使うかはお好みで。短いから普通は後者かな?

複数のテーブルに対してLEFT OUTER JOINしている場合

  • 次はちょっとややこしい
User.joins { corporation.outer.ceo.outer }
  • つまりはUserに対してCorporationLEFT OUTER JOINした後に、またさらにCeoLEFT OUTER JOINしている
  • これに対してはこう
User.left_joins(corporation: :ceo)
  • これがもしも
User.joins { corporation.ceo.outer }

とかだった場合(CorporatonINNER JOINCeoLEFT OUTER JOIN

User.left_joins(corporation: :ceo).where.not(Corporation.arel_table[:user_id].eq nil)

こんな感じで無理やりそれっぽくこじつけるか、諦めて一つ前のようにまとめてLEFT OUTER JOINしてしまうか、他の手立てを使うかを考えないといけない‥‥

まとめ

  • order関係は楽だけども、join周りが場合によってはしんどいかも

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
2