LoginSignup
124
117

More than 3 years have passed since last update.

whereにSQLの文字列を渡したくない!

Last updated at Posted at 2014-09-19

なんで文字列を渡したくないのか

  • なんとなく文字列で渡すというのが地に足がついてない感じでイヤ
  • DBの種類を変えると動かなくなる可能性がある
  • mergeができないことがある

例えばこんなの書きたくない

比較演算

target_age = 30
User.where('age >= ?', target_age)

or

target_name1 = '山田'
target_name2 = '田中'
User.where('name=? OR name=?', target_name1, target_name2)

like

target_letter = '田'
User.where('name like ?', "%#{target_letter}%")

Arel::tableを使う

ActiveRecordは内部でArelというSQL生成用ライブラリを使用している。
直接使うこともできるので、Arelで作ったSQLを文字列の代わりにwhereに渡してやろう、ということ。

比較演算

target_age = 30
User.where(User.arel_table[:age].gt(target_age))

ちなみに、
* = (equal) : eq
* < (less than) : lt
* <= (less than equal) : lteq
* > (greater than) : gt
* >= (greater than equal) : gteq

or

target_name1 = '山田'
target_name2 = '田中'
User.where(User.arel_table[:name].eq(target_name1).or(User.arel_table[:name].eq(target_name2)))

like

target_letter = '田'
User.where(User.arel_table[:name].matches("%#{target_letter}%"))

Squeelを使えばもっといい感じに!

Arel::tableでもとりあえず当初の目的は達成できたけど、如何せん長い…
Gemを入れてよければ、Squeelを使えばスッキリ書ける。

比較演算

target_age = 30
User.where{age >= target_age}

()ではなく{}を使う。

or

target_name1 = '山田'
target_name2 = '田中'
User.where{(name == target_name1) | (name == target_name2)}

||ではなく|
ちなみにandも&&ではなく&

like

target_letter = '田'
User.where{name =~ "%#{target_letter}%"}

これだけ見るとSqueelの完全勝利に見えるけど、
Arel::tableだとSQLの生成式を関数化して、複数箇所で使いまわせたりして便利だったりするのかな。

参考

ActiveRecord4でこんなSQLクエリどう書くの? Arel編
ActiveRecord4でこんなSQLクエリどう書くの? Squeel編

activerecord-hackery/squeel

124
117
1

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
124
117