ActiveRecord関連で初心者がつまづきやすいちょっとしたこと、やり方を忘れて何度も調べてしまうものをまとめておきます。随時更新する予定。

IN句をRailsの文法で書く

Arrayで渡します。

User.where(name: ['John','Smith','Richard'])
# = User.where("name IN ('John','Smith','Richard')")

PostgreSQL Array型を使う

PostgreSQLだと、Array型を使うことができます。

Arrayがどれかを含む

Array中に指定した要素のいずれかあるレコードを取得するにはANYを使います。

# Schedule.day_of_week = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
# 'Sun'を含むレコードを抽出
Schedule.where(":day = ANY(day_of_week)", :day => 'Sun')

子モデル/孫モデルの結合と絞込をうまいことやる

子モデルや孫モデルをキャッシュしたり(N+1対策)、子モデル・孫モデルで条件検索しようとした場合、joins/includes/eager_load/preloadを使いますが、
慣れないうちはどんな場合にどれを使えばいいかが難しいです。
その辺のことは他にすばらしいまとめがあるので、基本的な使い分けなどはこのあたりを参考に。

孫モデルをincludes

User.includes(friends: :address)
User.includes(:address, friends: [:address, :followers]) # 複数だとこうなる

子モデルをキャッシュ&絞込

子モデルで条件検索しつつ、子モデルのデータも使いたい時にはincludesとともにreferencesも指定する必要があるようです。

User.includes(:friends).references(:friends).where("friends.name = ?",'John')

joinsで複数の同レコードを返さないようにする

子レコードで絞込をしたい&キャッシュはしない時にはjoinsを使いますが、親レコードが複数の子レコードを持つ場合、子レコードの数だけ結果が返ってきてしまいます。

# Spot has_many :stations
Spot.all.size
# => 1
Spot.first.stations.size
# => 3

spots = Spot.joins(:stations).where("stations.name = hoge")
spots.size
# => 3

というような感じで、上の例だと同じレコードが3件返ってきてしまいます。
Spot.all.sizeが1なので、ここで戻ってきてほしいのは1件だけです。レコードが重複をせずuniqになるようにするにはdistinctを使います。

spots = Spot.joins(:stations).where("stations.name = hoge").distinct
spots.size
# => 1

参考 ActiveRecord::QueryMethods#includes

ORを使いこなす

普通の書き方は特に難しいことはありません。

Spot.where(prefecture: 'kanagawa').or(Spot.where(city: 'machida'))

子モデルでOR

john = User.find_by(name: 'John')
john.friends.where(gender: 'male').or(john.friends.where(name: 'Maria'))

# これはだめ
john.friends.where(gender: 'male').or(Friend.where(name: 'Maria'))

結合先(子モデル)の条件でORを使う

User.joins(:friends).where("friends.gender = male").or(User.joins(:friends).where("friends.name = Maria"))

# これもやっぱりだめ
User.joins(:friends).where("friends.gender = male").or(where("friends.name = Maria"))

ORの前と後ろはきちんと同じ形式になっていないとダメみたいです。

参考 ActiveRecord で join と or と and が入り混じった場合

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.