Ruby on RailsのActive Recordでは、whereメソッドにorメソッドを組み合わせられるのをご存じでしょうか。whereメソッドにSQLを直接記述することも可能ですが、whereメソッドとorメソッドを組み合わせて条件を指定することも可能です。
今回は、whereメソッドとorメソッドの使い方や組み合わせ方法について紹介します。
Ruby on RailsによるDBアクセス機能
Ruby on Railsは、必ずSQLデータベースに格納されたデータを利用します。しかしプログラムの中にSQLを埋め込んで、それを使う必要はありません。例えばデータアクセス用のActive Recordライブラリを使用すると、モデル名だけでSQLデータベースからデータを取得できます。
今回紹介するorメソッドは、Active Recordライブラリでデータを検索する際に、その条件の記述に利用します。orメソッドの使い方を紹介する前に、Ruby on RailsによるDBアクセス機能であるActive Recordライブラリを利用したデータ検索方法について解説します。
Active RecordでDBにアクセス
Ruby on Railsは、MVCモデルに基づいて作られていますが、Mに当たるModelとはデータのことです。そしてそのデータはSQLデータベースに格納されています。このようにRuby on RilasはSQLデータベースと連携して動作しており、この連携を担当するのがActive Recordです。
そのためRuby on Railsでは、Active Recordを利用することでSQLを意識することなくデータベースにアクセスできます。さらにActive Recordのメソッドを利用すれば、SQLの高度な検索機能をSQLの文法を意識せずに利用することが可能です。
検索はActive Recordのwhereメソッド
SQLでデータを検索するには、その条件をWHERE句で記述します。このWHERE句に当たるActive Recordのメソッドがwhereメソッドです。whereメソッドは、引数に検索条件を指定すると、その条件がSQLに変換されてデータベースを検索します。
whereメソッドの文法
モデル名.where( 条件 )
whereメソッドの使用例
target = client.where( id: 10 )
whereメソッドに条件はSQLに変換される
Active Recordのwhereメソッドに指定した条件がそのままSQLに反映されるので、Active Recordを使えばSQLを学ぶ必要がない、ということではありません。むしろwhereメソッドに指定する条件がSQLにどう反映されるかを意識して設定する必要があります。
例えばwhere句の引数に複数の条件を記述すると、指定した条件のAND検索が可能です。それがどうSQLに変換されるかを次に紹介します。
where句で複数の条件を指定する使い方
モデル名.where( 条件1, 条件2, … )
where句で複数の条件を指定した例
@target = client.where( id: 10, flg: 0 ).first
上記の例では次のようなSQLが実行されます。
SELECT 'client'.* FROM 'client' WHERE 'client'.'id' = 10 AND 'client'.'flg' = 0 LIMIT 1;
whereメソッドでOR検索するには
先ほどwhereメソッドに複数の条件を指定するとAND条件の検索が可能だと紹介しました。ではOR検索するにはどうすれば良いでしょうか。
whereメソッドにorメソッドを組み合わせることでOR条件の検索も可能です。次からorメソッドの使い方について紹介します。
Ruby on Rails5系からorメソッドが使える
Ruby on Railsのバージョン5よりActive RecordのwhereメソッドによるSQL生成手順が変更され、orメソッドが使えるようになりました。なおwhereメソッドはそれ以前から使えていますが、OR条件を実現するために面倒な書き方が必要でした。しかし、orメソッドを利用することで簡潔に記述することが可能です。
それ以前のバージョンでは今回紹介しているRuby on Railsのorメソッドは利用できまないので注意してください。
orメソッドの使い方
先ほど紹介したようにActive Recordのwhereメソッドには、SQLで検索する際の条件を記述します。AND条件の指定はwhereメソッド内に複数書くだけですが、OR条件を指定する場合、whereメソッドにorメソッドを組み合わせて記述します。
下記のOR条件の例を基にorメソッドの使い方を紹介します。
A or B
この場合、まずはwhereメソッドで条件Aを記述し、続いてドット「.」を使いorメソッドで条件Bを定義したwhere(B)を追加します。
モデル名.where(A).or(モデル名.where(B))
複数の条件を指定する方法
これまでActive Recordのwhereメソッドを用いた、2つの条件のANDとORの指定方法を紹介しましたが、AND条件は次のようにドットで接続して記述できます。
whereメソッドによるAND条件の書き方
モデル名.where(A, B)
モデル名.where(A).where(B)
どちらも「A AND B」の記述方法
このドットで条件を接続する書き方を使えば、3つ以上の条件の組み合わせも記述できます。
例えば、次のような3つの条件は、それぞれの条件を指定した3つのメソッドで作ることも可能です。
A and B or C
モデル名.where(A).where(B).or(モデル名.where(C))
ただし、ドットで接続した書き方の場合、左側の論理式から順番に評価されるので注意してください。つまり「A and B or C」では、先に「A and b」が評価され、続いて「A and B」の評価結果とCのorが評価されます。
mergeメソッドとorメソッドを組み合わせる
SQLの検索条件としてandまたはorを単純に組み合わせた条件であれば、これまで説明したようにwhereメソッドで記述できます。しかし、実際にはもっと複雑な検索条件のSQLも使われており、そのような場合は条件を括弧でくくって優先順位を設定します。
括弧を用いた条件を使ったSQLの例
SELECT * FROM model WHERE ( A or B ) and ( C or D ) ;
これをActive Recordのwhereメソッドとorメソッドを利用する場合、括弧に相当するメソッドを使い、その中にorメソッドを記述します。この括弧に相当するメソッドがmergeメソッドです。
括弧を使った条件
( A or B )
whereメソッドを使った書き方
モデル名.merge( モデル名.where(A).or( モデル名.where(B) ) )
そのため、先ほどのSQLの条件をActive Recordのmergeメソッドを組み合わせると、次のように記述できます。
括弧を使った複雑な条件
( A or B ) and ( C or D )
whereメソッドを使った書き方
モデル名
.merge( モデル名.where(A).or( モデル名.where(B) ) )
.merge( モデル名.where(C).or( モデル名.where(D) ) )
mergeメソッドとwhereメソッドを利用した例
次に括弧を用いた条件を使ったSQLで検索するためにActive Recordのwhereメソッドを使用した検索の例を紹介します。
括弧を使った条件のSQLで検索する例
def check @spec = Hash.new @spec = Spec.merge(Spec.where(a:1).or(Spec.where(b:0))) .merge(Spec.where(c:0).or(Spec.where(d:0))).first end
上記の検索により、下記のSQLが実行されます。
SELECT `specs`.* FROM `specs` WHERE (`specs`.`a` = 1 OR `specs`.`b` = 0) AND (`specs`.`c` = 0 OR `specs`.`d` = 0) ORDER BY `specs`.`id` ASC LIMIT 1
まとめ
これまで紹介したようにRuby on Railsのバージョン5以降では、Active Recordのwhereメソッドで条件を設定する際、orメソッドを利用することが可能です。さらにmergeメソッドとorメソッドを組み合わせれば、複雑な条件のSQLを設定できます。
なおSQLの利用方法は、1つのテーブルから指定した条件のデータを抽出するだけではありません。複数のテーブルを接続し、そこに含まれる値の抽出条件を設定したデータを抽出することが可能です。
今回紹介したwhereメソッドやorメソッドは、そのようなテーブル結合を含むSQLの生成にも利用できるので、ぜひ活用してください。