Railsアプリケーション開発中に、WHERE A and (B or C)
のようなSQLをActiveRecordのデータアクセスメソッドで書くときにどうすれば良いのか少しハマったのでメモとして残します。
SQL
SELECT *
FROM model
WHERE A and (B or C) ;
結論
merge
メソッドを使用する。
括弧に該当するメソッドがmerge
メソッドとなる。
ActiveRecord
Model.where(A).merge(where(B).or(where(C)))
例: ポケモン
例えば、こんな感じのポケモンテーブルがあったとする
db/migrate/pokemon.rb
class Pokemons < ActiveRecord::Migration[5.2]
def change
create_table :pokemons do |t|
t.string name
t.string type
end
end
end
idが1~10かつ(炎タイプまたは水タイプ)のポケモンのみを取得したい場合
SQLで書くならこうなる
SQL
SELECT *
FROM pokemon
WHERE id BETWEEN 1 AND 10
AND (type = '炎' OR type = '水');
ActivrRecordのメソッドを使用すると・・・
ActiveRecord
@pokemons = Pokemon.where(id: 1..10).merge(where(type: '炎').or(where(type: '水')))
この部分だけ、何度も取得する必要がある場合は、pokemonモデルにscope
として定義しても良い
pokemon.rb
scope :filter_type, -> { merge(where(type: '炎').or(where(type: '水'))) }
// 呼び出し先
@pokemons = Pokemon.filter_type
おまけ
WHERE A and (B or C or D)
Model.where(A).merge(where(B).or(where(C)).or(where(D)))
WHERE (A or B) and (C or D)
Model.merge(where(A).or(where(B))).merge(where(C)).or(where(D)))
参考