ActiveRecordで複数条件のorクエリまたはinクエリを投げる(Rails小ネタ)
ActiveRecordでor検索をしようと思うと、意外と簡単にはできない。
Table.where(id: 1).or(id: 2) とかでできそうなものだができない。
真面目にやるには、Arelを使ってやるのが一番のようだ。
http://techracho.bpsinc.jp/tsunekawa/2013_05_24/8502
非常に出来合いのコードだが、or検索のscopeを作成した。(SQLインジェクション対策はなし。プレースホルダを使うscopeってどう書くの?)
下記のように呼び出す。
Table.or([{id: 1,val: 2},{id:4,val:5}]) #=> (id=1 and val=2) or (id=4 and val=5)
でも、結局 Table.where(id: 1).or(id: 2)はできない...(おぃ)
scope :or, ->(condition){
where(condition) unless condition.class == Array
table_name = self.table_name
sql = condition.map{|cond|
partial = cond.map{|col,val|
%{"#{table_name}"."#{col}" = #{sanitize(val)}}
}.join(" AND ")
"(#{partial})"
}.join(" OR ")
where(sql)
}
また、PostgreSQLは複数カラムのwhere INができるので、inのscopeも作成した。http://blog.fusic.co.jp/archives/1765
下記のように呼び出す。
Table.in([{id: 1,val: 2},{id:4,val:5}]) #=> (id,val) IN ( (1,2),(4,5) )
scope :in, ->(condition){
where(condition) unless condition.class == Array
table_name = self.table_name
columns_sql = condition.first.map{|col,val| %{"#{table_name}"."#{col}"} }.join(" , ")
columns = condition.first.map{|col,val| col }
values = condition.map{|cond|
value = columns.map{|col| sanitize(cond[col]) }.join(" , ")
"(#{value})"
}.join(" , ")
where("(#{columns_sql}) IN (#{values})")
}